#include "StdAfx.h" #include "AlignFinder.h" #include "CHImageControls/CHImageProcess.h" #include #include #include "EdgeFind.h" using namespace CHImageControls; inline bool CompareMaxSize(SPixelBlob& a, SPixelBlob& b) { return (a.dMatchValue > b.dMatchValue); } CAlignFinder::CAlignFinder(int nIndex) : m_nIndex(nIndex) { Reset(); } CAlignFinder::~CAlignFinder(void) { Reset(); } void CAlignFinder::Reset() { ResetImages(); m_pTempImage = NULL; m_findParam.Reset(); } void CAlignFinder::ResetImages() { m_SourceImage.ReleaseImage(); m_EdgeImage.ReleaseImage(); m_ThresImage.ReleaseImage(); m_BlobImage.ReleaseImage(); m_ResultImage.ReleaseImage(); } BOOL CAlignFinder::SaveSourceImage(const CString& strFilename) { return m_SourceImage.SaveImage(strFilename); } BOOL CAlignFinder::SaveEdgeImage(const CString& strFilename) { return m_EdgeImage.SaveImage(strFilename); } BOOL CAlignFinder::SaveThresholdImage(const CString& strFilename) { return m_ThresImage.SaveImage(strFilename); } BOOL CAlignFinder::SaveBlobImage(const CString& strFilename) { return m_BlobImage.SaveImage(strFilename); } BOOL CAlignFinder::SaveResultImage(const CString& strFilename) { return m_ResultImage.SaveImage(strFilename); } BOOL CAlignFinder::GetSourceImage(CCHImageData *pImageData) { return m_SourceImage.CopyImageTo(pImageData); } BOOL CAlignFinder::GetEdgeImage(CCHImageData *pImageData) { return m_EdgeImage.CopyImageTo(pImageData); } BOOL CAlignFinder::GetThresholdImage(CCHImageData *pImageData) { return m_ThresImage.CopyImageTo(pImageData); } BOOL CAlignFinder::GetBlobImage(CCHImageData *pImageData) { return m_BlobImage.CopyImageTo(pImageData); } BOOL CAlignFinder::GetResultImage(CCHImageData *pImageData) { return m_ResultImage.CopyImageTo(pImageData); } SAlignFindResult CAlignFinder::FindAlign(CCHImageData *pImageData, const SAlignFindParam& findParam, CCHImageData *pTempImage) { /////////////////////////////////////IMAGE LOAD FOR TEST !!!! ///////////////////// // CCHImageData *tempImage = new CCHImageData; // tempImage->LoadImageW(_T("D:\\Align1.BMP")); // // m_pTempImage = pTempImage; // m_findParam = findParam; // // return FindAlign(tempImage, pTempImage m_pTempImage = pTempImage; m_findParam = findParam; return FindAlign(pImageData, pTempImage); } SAlignFindResult CAlignFinder::FindAlign(CCHImageData *pImageData, CCHImageData *pTempImage) { m_pTempImage = pTempImage; //¾ó¶óÀÎ ÆÄÀεå if (pImageData==NULL) return SAlignFindResult(); if (pImageData->GetImageExist()==FALSE) return SAlignFindResult(); if (pImageData->GetChannels()!=1) return SAlignFindResult(); else { int a = pImageData->GetChannels(); } return FindAlign((BYTE*)pImageData->GetImageBuffer(), pImageData->GetWidth(), pImageData->GetHeight()); } SAlignFindResult CAlignFinder::FindAlign(BYTE* pImage, int nWidth, int nHeight, const SAlignFindParam& findParam) { m_pTempImage = NULL; m_findParam = findParam; return FindAlign(pImage, nWidth, nHeight); } SAlignFindResult CAlignFinder::FindAlign(BYTE* pImage, int nWidth, int nHeight) { SAlignFindResult findResult; if (pImage==NULL) return findResult; ResetImages(); findResult.nResultCode = 0; // step1. Áß°£°á°ú À̹ÌÁö »ý¼º if (m_SourceImage.CreateImage(nWidth, nHeight)==FALSE) return findResult; if (m_EdgeImage.CreateImage(nWidth, nHeight)==FALSE) return findResult; memcpy(m_SourceImage.GetImageBuffer(), pImage, sizeof(BYTE)*nWidth*nHeight); // step3. matching if (FindAlignMatching(findResult)==1) { return findResult; } /*< LYW 20211013 - #3671 Delete Start >*/ // step2. edge find // if (FindAlignEdge(findResult) == 1) // { // return findResult; // } /*< LYW 20211013 - #3671 Delete End >*/ return findResult; } int CAlignFinder::FindAlignMatching(SAlignFindResult& findResult) { findResult.nResultProcess = AlignProcess_Match; if (m_findParam.bMatchProcess==FALSE) { return 0; } if (m_pTempImage==NULL) { findResult.nResultCode = AlignMatch_None; return 0; } if (!m_pTempImage->GetImageExist()) { findResult.nResultCode = AlignMatch_NoTemplate; return 0; } if (m_pTempImage->GetChannels()!=1) { findResult.nResultCode = AlignMatch_NotOneChannels; return 0; } double dResultX, dResultY; CCHImageData resultImage; if (CCHImageProcess::ImageMatching(&m_SourceImage, m_pTempImage, dResultX, dResultY, findResult.dMatchValue, &resultImage)!=ResultSuccess) { findResult.nResultCode = AlignMatch_MatchFail; return 0; } CCHImageData tempImage; CCHImageProcess::ImageNormalize(&resultImage, &m_BlobImage, 0, 255); /*< LYW 20211013 - #3671 Delete Start >*/ // if (findResult.dMatchValue < m_findParam.dMatchRate) // { // findResult.nResultCode = AlignMatch_LowScore; // return 0; // } /*< LYW 20211013 - #3671 Delete End >*/ // step5. Make Result À̹ÌÁö findResult.nResultCode = AlignMatch_Success; double dHalfWidth = double(m_pTempImage->GetWidth()) / 2.0; double dHalfHeight = double(m_pTempImage->GetHeight()) / 2.0; findResult.dPosX = dResultX + dHalfWidth; findResult.dPosY = dResultY + dHalfHeight; if (m_SourceImage.CopyImageTo(&m_ResultImage)) { m_ResultImage.DrawRectangle(CPoint((int)(dResultX+0.5), (int)(dResultY+0.5)), CPoint((int)(dResultX+m_pTempImage->GetWidth()+0.5), (int)(dResultY+m_pTempImage->GetHeight()+0.5)), RGB(255,255,255), 2); } /*< LYW 20211013 - #3671 ADD Start >*/ if (findResult.dMatchValue < m_findParam.dMatchRate) { findResult.nResultCode = AlignMatch_LowScore; return 0; } /*< LYW 20211013 - #3671 ADD End >*/ return 1; } int CAlignFinder::FindAlignEdge(SAlignFindResult& findResult) { findResult.nResultProcess = AlignProcess_Edge; if (m_findParam.bEdgeProcess==FALSE) { return AlignEdge_None; } // step1. Sobel Edge ¿¬»ê int nWidth = m_SourceImage.GetWidth(); int nHeight = m_SourceImage.GetHeight(); if (ImageSobelEdge((BYTE*)m_SourceImage.GetImageBuffer(), (BYTE*)m_EdgeImage.GetImageBuffer(), nWidth, nHeight)!=1) { findResult.nResultCode = AlignEdge_EdgeFail; return 0; } // step2. Binary Threshold ¿¬»ê if (m_EdgeImage.CopyImageTo(&m_ThresImage)==FALSE) { findResult.nResultCode = AlignEdge_None; return 0; } if (ImageThresholding((BYTE*)m_ThresImage.GetImageBuffer(), nWidth, nHeight, m_findParam.nEdgeThreshold)!=1) { findResult.nResultCode = AlignEdge_BinaryFail; return 0; } // step3. Blob Analysis ¿¬»ê if (m_ThresImage.CopyImageTo(&m_BlobImage)==FALSE) { findResult.nResultCode = AlignEdge_None; return 0; } VectorPixelBlob pixelBlob; if (ImageBlobAnalysis((BYTE*)m_BlobImage.GetImageBuffer(), nWidth, nHeight, pixelBlob, m_findParam.nMergeRange, m_findParam.nAlignHeight, m_findParam.nAlignWidth)!=1) { findResult.nResultCode = AlignEdge_BlobFail; return 0; } // step4. Blob Matching °ª °è»ê //m_findParam.bMeasureThickness = 1; // Çü¸ñ¾¾ À̰ŠÁÖ¼® ²À°É¾î¿ä Edge Find ¾ÈµÇ¿ä if (m_findParam.bMeasureThickness) { if (AlignMeasureThickness((BYTE*)m_BlobImage.GetImageBuffer(), nWidth, nHeight, pixelBlob, m_findParam)==0) { if(pixelBlob.size() > 0) { findResult.dMatchValue = pixelBlob[0].dMatchValue; } findResult.nResultCode = AlignEdge_BlobFail; return 0; } } findResult.dMatchValue = pixelBlob[0].dMatchValue; if (findResult.dMatchValue TopKernel = _mm_packus_epi16(TopKernel, TopKernel); // last result _mm_storel_epi64( (__m128i*)(pDstImageX), TopKernel); pSrcImageX += 8; pDstImageX += 8; } *(pDstImageX-nLast) = 0; } memset(pDstImage, 0, nWidth); memset(pDstImage+((nHeight-1)*nWidth), 0, nWidth); return 1; } int CAlignFinder::ImageThresholding(BYTE* pImage, int nWidth, int nHeight, int nThresValue) { if (pImage==NULL) return 0; register BYTE *pBuffer = pImage; __m128i _x80 = _mm_set1_epi8('\x80'); __m128i ThresData = _mm_set1_epi8(UCHAR(nThresValue)^0x80); __m128i v0, v1; register int i; register int nTotalSize = nWidth*nHeight; for(i=0; i<=nTotalSize-32; i+=32 ) { v0 = _mm_loadu_si128( (const __m128i*)(pBuffer) ); v1 = _mm_loadu_si128( (const __m128i*)(pBuffer+16) ); v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), ThresData ); v1 = _mm_cmpgt_epi8( _mm_xor_si128(v1, _x80), ThresData ); _mm_storeu_si128( (__m128i*)(pBuffer), v0 ); _mm_storeu_si128( (__m128i*)(pBuffer+16), v1 ); pBuffer+=32; } for( ; i <=nTotalSize-8; i+=8 ) { v0 = _mm_loadl_epi64( (const __m128i*)(pBuffer) ); v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), ThresData ); _mm_storel_epi64( (__m128i*)(pBuffer), v0 ); pBuffer+=8; } for (; inThresValue) ? 255: 0; } return 1; } int CAlignFinder::ImageBlobAnalysis(BYTE *pImage, int nWidth, int nHeight, VectorPixelBlob& vectorBlob, int nBlob, int nAlignWidth, int nAlignHeight) { if (pImage==NULL) return 0; int i, j, y, x; // top & bottom margin BYTE *pBuf1 = pImage; BYTE *pBuf2 = pImage + (nHeight-1)*nWidth; for (i=0; i vectorPixel; SPixelBlob pixelBlob; register BYTE *pSrcImgY = pImage + (nBlob*nWidth) + nBlob; register BYTE *pSrcImgX, *pSubX, *pSubY; int nBlobMin = -nBlob; int nBlobMax = nBlob+1; for (i=nBlob; i 200) { *pSrcImgX = 128; vectorPixel.push_back(CPoint(j, i)); // new pixel blob pixelBlob.Reset(); while ((nSize=vectorPixel.size())>0) { x = vectorPixel[nSize-1].x; y = vectorPixel[nSize-1].y; // delete end point vectorPixel.pop_back(); // add point to blob pixelBlob.vectorPoint.push_back(CPoint(x, y)); // get current point pSubY = pImage + ((y+nBlobMin)*nWidth) + (x+nBlobMin); for (int sy=nBlobMin; sy 200) { *pSubX = 128; vectorPixel.push_back(CPoint(x+sx, y+sy)); } pSubX++; } pSubY += nWidth; } if (pixelBlob.nLeft>x) pixelBlob.nLeft = x; if (pixelBlob.nRighty) pixelBlob.nTop = y; if (pixelBlob.nBottom nWidth - nRefWidth / 2 || ptResult.y < nRefHeight / 2 || ptResult.y > nHeight - nRefHeight / 2) return MeasureResult; CRect rtROI; const int nBaseWidth = nRefWidth / 9; const int nBaseHeight = nRefHeight / 9; //Left rtROI.left = ptResult.x - nRefWidth / 2 + nBaseWidth; rtROI.top = ptResult.y - nRefHeight / 2; rtROI.right = rtROI.left + nBaseWidth; rtROI.bottom = rtROI.top + nRefHeight; MeasureResult.rtSizeL.left = rtROI.left; MeasureResult.rtSizeL.right = rtROI.right; MeasureResult.rtSizeL.top = CEdgeFind::ImageProjection_Vert(pProcImg, nWidth, nHeight, rtROI, 100, 5, 1); MeasureResult.rtSizeL.bottom = CEdgeFind::ImageProjection_Vert_R(pProcImg, nWidth, nHeight, rtROI, 100, 5, 1); //Right rtROI.right = ptResult.x + nRefWidth / 2 - nBaseWidth; rtROI.left = rtROI.right - nBaseWidth; MeasureResult.rtSizeR.left = rtROI.left; MeasureResult.rtSizeR.right = rtROI.right; MeasureResult.rtSizeR.top = CEdgeFind::ImageProjection_Vert(pProcImg, nWidth, nHeight, rtROI, 100, 5, 1); MeasureResult.rtSizeR.bottom = CEdgeFind::ImageProjection_Vert_R(pProcImg, nWidth, nHeight, rtROI, 100, 5, 1); //top rtROI.left = ptResult.x - nRefWidth / 2; rtROI.top = ptResult.y - nRefHeight / 2 + nBaseHeight; rtROI.right = rtROI.left + nRefWidth; rtROI.bottom = rtROI.top + nBaseHeight; MeasureResult.rtSizeT.top = rtROI.top; MeasureResult.rtSizeT.bottom = rtROI.bottom; MeasureResult.rtSizeT.left = CEdgeFind::ImageProjection(pProcImg, nWidth, nHeight, rtROI, 100, 5, 1); MeasureResult.rtSizeT.right = CEdgeFind::ImageProjection_R(pProcImg, nWidth, nHeight, rtROI, 100, 5, 1); //bottom rtROI.bottom = ptResult.y + nRefHeight / 2 - nBaseHeight; rtROI.top = rtROI.bottom - nBaseHeight; MeasureResult.rtSizeB.top = rtROI.top; MeasureResult.rtSizeB.bottom = rtROI.bottom; MeasureResult.rtSizeB.left = CEdgeFind::ImageProjection(pProcImg, nWidth, nHeight, rtROI, 100, 5, 1); MeasureResult.rtSizeB.right = CEdgeFind::ImageProjection_R(pProcImg, nWidth, nHeight, rtROI, 100, 5, 1); return MeasureResult; } int CAlignFinder::AlignMeasureThickness( BYTE *pImage, int nWidth, int nHeight, VectorPixelBlob& vectorBlob, const SAlignFindParam& sAlignFindParam ) { int nLRThickness = sAlignFindParam.nEDThicknessLR; int nTBThickness = sAlignFindParam.nEDThicknessTB; int nThicknessRange = sAlignFindParam.nEDThicknessRange; VectorPixelBlob vecResult; for (VectorPixelBlobIt it=vectorBlob.begin(); it!=vectorBlob.end(); it++) { // check score if (it->dMatchValue >= sAlignFindParam.dEdgeRate) { CPoint ptResult; ptResult.x = it->GetCenterX(); ptResult.y = it->GetCenterY(); it->sThicknessResult = FindAlignMarkThickness(pImage, nWidth, nHeight, ptResult, it->GetWidth(), it->GetHeight()); int lh = it->sThicknessResult.rtSizeL.Height(); int rh = it->sThicknessResult.rtSizeR.Height(); int tw = it->sThicknessResult.rtSizeT.Width(); int bw = it->sThicknessResult.rtSizeB.Width(); if(it->sThicknessResult.IsAllSuccess() == FALSE /* || it->sThicknessResult.rtSizeL.Height() > nLRThickness + nThicknessRange || it->sThicknessResult.rtSizeL.Height() < nLRThickness - nThicknessRange || it->sThicknessResult.rtSizeR.Height() > nLRThickness + nThicknessRange || it->sThicknessResult.rtSizeR.Height() < nLRThickness - nThicknessRange || it->sThicknessResult.rtSizeT.Width() > nTBThickness + nThicknessRange || it->sThicknessResult.rtSizeT.Width() < nTBThickness - nThicknessRange || it->sThicknessResult.rtSizeB.Width() > nTBThickness + nThicknessRange || it->sThicknessResult.rtSizeB.Width() < nTBThickness - nThicknessRange */ || lh > nLRThickness + nThicknessRange || lh < nLRThickness - nThicknessRange || rh > nLRThickness + nThicknessRange || rh < nLRThickness - nThicknessRange || tw > nTBThickness + nThicknessRange || tw < nTBThickness - nThicknessRange || bw > nTBThickness + nThicknessRange || bw < nTBThickness - nThicknessRange ) { continue; } vecResult.push_back(*it); } } vectorBlob = vecResult; return (int)vectorBlob.size(); }