...
Patches flow
FrameProc
procCompositeChannelSingleDetectionAlgo
1
... components and functional diagram combined
Drawing Igor Polkovnikov
1
2
3
4
6
5
1
1
2
sDefectPatchGeometry defectPatGeorm
sDefectPatchGeometry defectPatGeorm; // This is needed for stitching.
defectPatGeorm.fXMicron = xyPatchRecipeRequests.xyPatchRequests[i].dXum;
defectPatGeorm.fYMicron = xyPatchRecipeRequests.xyPatchRequests[i].dYum;
defectPatGeorm.fHeightMicron = IgNS::DistBtwCenters ( nNumTangentialPixels , sFrameStr.dPxlSizeTngntlUm);
defectPatGeorm.fWidthMicron = IgNS::DistBtwCenters ( nNumRadialPixels , sFrameStr.dPxlSizeRdlUm );
defectPatGeorm.uPatchSizeRdl = xyPatchRecipeRequests.nNumRadialPixels;
defectPatGeorm.uPatchSizeTngntl = xyPatchRecipeRequests.nNumTangentialPixels;
SxyPatchInfo xyPatInfo ( defectPatGeorm.fXMicron, defectPatGeorm.fYMicron, defectPatGeorm.fHeightMicron, defectPatGeorm.fWidthMicron ); // calculates vodRadiTheta
defectPatGeorm.rFullPatchRadiTheta = xyPatInfo.patchRT;
for (auto iChannel = m_oPhysicalChannelsParamsMap.begin(), iterEnd = m_oPhysicalChannelsParamsMap.end();
if (!bSkipXYPatchProcessing)
m_pSetupParam->oXYPatchRecipeRequests
XY Patch Flow
From information originated from recipe or
algoconfig.csv find if a requested
XY location is within the current frame
(see below)
for a particular XY patch, for every channel
generate_XYPatInfo_3(
// returns xyInfo. It contains SOME of the data.
For every XY patch request, check
if a channel of the current frame contains
at least one full patch corner
CxyCorrectionReversal::calculateRowAndColumnIndex (
// find center
IgNS::normalize2Max_RectInt
Make sure that for any number of corners,
1,2,3 or 4, the index area of the partial patch
within the frame is rectangular and
includes all available corners.
Index area will always be slightly
larger-or-equal than the area suggested by
the full defect patch geometry.
GrabPatchRowCol_StartEnd2 (
// if all 4 corners are inside, use older function
// Filter out patches which do not belong to the current frame
bool bPatchIsWithinAtLeastOneChannel;
// proceed if at least one channel contains a partial patch
Calculate
XY patch global coordinates and sizes
xyInfo[nCh] // fill all partial patch requestsinformation for every channel
Complete
XY partial or full patch request information
voXYPatchInfo_output
Prepare buffers
oCompositorHelper.Serialize_OutputsCompositorBufferAndGetPatchBuf(pOutData
voPairPartialPatchesXY
FillPatch(pInData, voPairPartialPatchesXY, "PartialPatchesXY");
FillPartialXYPatch(voPairPartialPatchesXY);
Extract partial and full XY patches and
serialize patch requests
TwoDimCompositorLite
::CTwoDimCompositorAlgo_stitchXYPatches(
pOutData
m_mapPartialXYPatches
XY Patch Flow
//Accumulate and group partial XY patches
Accumulate and group coming
partial XY patches and requests.
When ready, do stitching
prepare data ... then:
IgNS::FullPatch fullPatch;
// this code is for printf reporting only
for every channel
stitchPatches (
CiterativeRmsCalculator::calculateWithInternalMean(pPatch
1
2
Calculate statistics for a patch per channel
voCompletePatchesToSerialize.push_back(
...
::generateOutputPatchBuffer(pOutData
Serialize to NGS
3
IgNS::FullPatch fullPatch;
if ( !fullPatch.pickUp (vpAllPartialPatches, nChannel ) )
Try to find a complete patch.
If found, use it
p3->polarRT.ifOXCrossing()
p3->polarRT.convertToPositive()
p3->polarRT.normalizeForOXCrossing()
1
2
fullPatch.assemble (
If not, assemble the full patch by coping
partial patches into the full patch buffer
in accordance with their global polar
coordinates
generate_XYPatInfo_2(
// returns xyInfo. It contains SOME of the data.
CxyCorrectionReversal::calculateRowAndColumnIndex (
IgNS::normalize2Max_RectInt
GrabPatchRowCol_StartEnd2 (
// if all 4 corners are inside, use older function
CxyCorrectionReversal::calculateRowAndColumnIndex (
// find corners
RectPolar_From_Indexes_func (
// sets polar coordinates of the partial patch corner pixels given by indexes
oChannelParams.funcCalculateXYLocation
polarRT
stitchPatches (
IgNS::FullPatch fullPatch;
if not
p3->polarRT.normalize_t()
1
2
fullPatch.assemble (
vector<sPatchDescriptor*> vpAllPartialPatches
sDefectPatchGeometry patchGeometry
UINT8 * pPatchDataOut
data
stichPatches() copies partial patches from vpAllPartialPatches vector
into a pre-allocated pPatchDataOut buffer in accordance with patchGeometry.
Firstly, the vpAllPartialPatches is verified if it contains a partial patch with the same size as a full patch.
If so, it is copied as is and it is done.
The code is desinged with the help of small classes:
Buffer - a memory buffer;
RectIndexes - a set of indexes which serve are integer coordinates;
SegmentRect - a generalized iterator to a rectangular area on a memory buffer (think pointers).
pickUp(
RectIndexes riPartPatch ( 0, p3->nRowEnd - p3->nRowStart, 0, p3->nColEnd - p3->nColStart);
if (riPartPatch.nCols() == this->m_riFullPatch.nCols() && riPartPatch.nRows() == this->m_riFullPatch.nRows() )
CopySegments (&segIntersectionTo, segPartPatchFrom);
Prepare partial patches for OX crossing
Before stitching, partial patches global polar coordinates must be prepared.
If at least one partial patch or the full patch geometry is crossing positive OX axis, the polar coordinates of all other
partial patches and the full patch of the set may not be in the same range. Some of them may be in [0,2Pi[,
other in ]1.5Pi, 2.5Pi[. All of the must be in the same range ]1.5Pi,2.5Pi[
The idea of partial patch stitching based on polar coordinates is this.
Patches we deal with are small, so the curvature can be ignored, i.e. it can be assumed that polar coordinates
of the patch corners can be treated as orthogonal.
It is assumed as well, that the partial patches row directions (tangential) are reasonably well matching circles,
i.e. partial patch sides are assumed parallel between each other and to frame tangential sides.
Every partial patch has polar coordinates of its corners calculated. The full patch likewise has its corner coordinates calculated.
Than, knowing the patches sizes in pixels and pixel sizes in um, we can trasform polar coordinates given as doubles
into integer index coordinates. Then, we can copy partial patch buffers onto a full patch bufer in accordance with the indexes.
Some empty space may persist. It is possible to enlarge the partial patch cooridinates and cut larger patches in an attempt
fill up the gaps with somewhat.
RectIndexes riCoordPartPatch_in_FullPatch
= coordRelativeTransform2 (
m_rpFullPatch.lt0, // Full patch origin in polar (coordinates of left-top corner)
rpPartPatch.lt0, // partial patch origin in polar
originPartPatch, // origin indexes in the full patch. They are 0-s
m_k001, // transformation coefficients between polar and indexes within full patch area
(int)riPartPatch.nCols(), // nCols of the partial patch
(int)riPartPatch.nRows() ); // nRows of the partial patch
fullPatch.init (
2
double drPix = -( (_rpFullPatch.lt0.r - _rpFullPatch.rt3.r) / (uPatchSizeRdl-1) );
double dtPix = ( (_rpFullPatch.lb1.t - _rpFullPatch.lt0.t) / (uPatchSizeTngntl-1) );
fullPatch object is initialized with full patch data obtained from patchGeometry.
drPix and dtPix are coefficients used in further transformations.
_rpFullPatch contains polar coordinates of the full patch centers of its corner pixels.
uPatchSizeRdl and Tngntl are full patch sizes in pixels.
drPix is how much distance (in distance units used) is between centers of
neighboring pixels in radial direction.
dtPix is how much anlge in radian is between centers of
neighboring pixels in tangential direction.
These values are stored in m_k001 for further reference. They are coefficients of
transformation between pseudo orthogonal patch coordinates and indexes for
all partial patches covering the full patch area.
(-) sign represents the opposite direction of r-coordinate axis and the patch radial indexes
m_k001
1
RectIndexes coordRelativeTransform2 ( Polar & rDst, Polar & rSrc, OriginOffset originDst, Polar dPix, int colsSrc, int rowsSrc )
// dPix is mk/pix
{
RectIndexes Frame;
Frame.nColStart = originDst.x + (s32)round( (rSrc.r-rDst.r) / dPix.r );
Frame.nRowStart = originDst.y + (s32)round( (rSrc.t-rDst.t) / dPix.t );
Frame.setEnds (colsSrc, rowsSrc); // just add all the pixels
This function maps the origin pixel (of left-top corner) of a partial patch into the index-space of the full patch.
Mapping of other corners is found by adding size of the partial patch to the found origin.
RectIndexes rIntersection = m_riFullPatch;
rIntersection.intersection ( riCoordPartPatch_in_FullPatch );
2
An intersection of the full patch pixel area and the mapping into it of the partial patch is found
if (!rIntersection.isNormal())
continue; // there is no intersection
for every partial patch
3
If there is no intersection, continue with the next partial patch
...
riPPFrom.offset(off);
The intersection is mapped back into the index coordinates of the partial patch
if (!riPPFrom.within (riPartPatch)
If it is within the partial patch coordinates - fine
riPPFromCorrected.intersection (riPPFrom);
If it is not within, find intersection.
This intersection is an area in the index space of the partial patch
which is going to be mapped successfully back into full patch index space.
segPartPatchFrom.set
a Segment (pointers) is set to the partial patch buffer to copy from
segIntersectionTo.set
a Segment (pointers) is set to the full patch buffer to copy to
CopySegments (&segIntersectionTo, segPartPatchFrom);
Copy the segments from one buffer to another.
... and go to the next partial patch.
4
5
6
7
8
9
DefectPatchTest
To understand fully how it works, go to the DefectPatchTest unit test project and step through the testing code.
I highly recommend the use of the project for development and testing.
1
2
If a full patch is not found, ...
p3->polarRT.ifOXCrossing()
p3->polarRT.normalizeForOXCrossing()
All patches have to be normalized in such way that polar tangential coordinates of the lower-index pixels
are always positive and less than the coordinates of higher-index pixels. normalize_t() does it.
polarRT should be already normalized in the constructure, but just in case it is repeated here.
Check if any of the partial or full patches is crossing positive OX
If at least one is crossing OX, normalize all to the ]1.5Pi,2.5Pi[ range
for complete descriptioin,
follow the line
find a rectangle of indexes within full patch index space
where a partial patch is mapped in accordance with global
polar coordinates or the full patch, the partial patch, and coefficients
found for the full patch.
Errors ! Ask Dhruba
Needs verification
Under development
Runs now