Thursday, August 28, 2014

Pattern Recognition, Find a Mark in an Image

Pattern Recognition, Find a Mark in an Image

To find a specific mark in an image we use statistical correlation to compare a reference image that defines the mark to a test image that may contain the mark. The result image is filled with the correlation coefficient data. The pixel in the result image with the highest value is the most probable location for the mark.


This procedure supports grayscale images. Use the Victor Library conversion functions to convert color or black and white images to 8-bit grayscale. In general, the steps are:
  • determine the dimensions and pixel depth of the test and reference images
  • allocate buffer space for the images
  • load the images
  • fill the result image with correlation coefficient data calculated between the test image and the reference image
  • sort the correlation coefficient data to determine the most probable location of the mark

source image pattern recognition image containing the pattern result image pattern recognition
Test image Reference image Result image, mark found at (84, 213)

The result image is filled with pixel data that represent the correlation coefficient calculated between the reference image and the test image at each pixel location. The pixel values can range from zero (negative correlation) through 128 (no correlation) up to 255 (perfect positive correlation). A negative correlation would mean a good match with the negative image of the reference mark.
The brightest pixel in the result image represents the most probable location of the reference mark. In this case that is at location (84, 213).




Find a Mark - the VB.NET Source Code

Requires Victor Image Processing Library for 32-bit Windows v 6.0 or higher.
// Add viclib as a reference in your VB.NET project
   Private Function findmark(ByVal srcimg As vicwin.imgdes, ByVal oprimg As vicwin.imgdes, ByVal resimg As vicwin.imgdes, ByVal ptarray As vicwin.COORD_VAL(), ByVal numelem As Long) As Long
        Dim rcode As Long

        '   Fill the result image with correlation coefficient data
        rcode = vicwin.correlateimages(srcimg, oprimg, resimg)
        If (rcode = vicwin.NO_ERROR) Then
            '  The pixel data in the result image will be sorted
            '  and placed in the array in descending order
            rcode = vicwin.sortpixelsbyval(resimg, ptarray(0), numelem)

        End If

        findmark = rcode

    End Function


    Private Sub mnu_findmark_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnu_findmark.Click
        Dim rcode As Long
        Dim testimage As vicwin.imgdes
        Dim markimage As vicwin.imgdes
        Dim testfile As vicwin.JpegData
        Dim markfile As vicwin.JpegData
        Dim scols, srows, ocols, orows As Long
        Dim numelem As Long

        ' For easier understanding of the sample code no error checking is performed here
        ' but recognize that you should always test the return code to verify that each function is successful 
        rcode = vicwin.jpeginfo("testc.jpg", testfile)
        rcode = vicwin.allocimage(testimage, testfile.width, testfile.length, testfile.vbitcount)
        rcode = vicwin.loadjpg("testc.jpg", testimage)

        rcode = vicwin.jpeginfo("register.jpg", markfile)
        rcode = vicwin.allocimage(markimage, markfile.width, markfile.length, markfile.vbitcount)
        rcode = vicwin.loadjpg("register.jpg", markimage)

        scols = testimage.endx - testimage.stx + 1
        srows = testimage.endy - testimage.sty + 1
        ocols = markimage.endx - markimage.stx + 1
        orows = markimage.endy - markimage.sty + 1


        ' Allocate an array to hold the pixel data for the sorting
        numelem = scols * srows
        Dim ptarray(numelem) As vicwin.COORD_VAL

        rcode = findmark(testimage, markimage, testimage, ptarray, numelem)
        If (rcode = vicwin.NO_ERROR) Then
            MsgBox("Most probable location for mark: " & ptarray(0).val & "  (" & ptarray(0).x & "," & ptarray(0).y & ")")
        End If

        rcode = vicwin.savejpg("testr.jpg", testimage, 50)
        vicwin.freeimage(markimage)
        vicwin.freeimage(testimage)
    End Sub





Find a Mark - the C# Source Code

Requires Victor Image Processing Library for 32-bit Windows v 6.0 or higher.
                case "findmark":   // Assumes three existing images:
                                   // the subject image is in simage, the register mark is in oimage, and the result will be placed in rimage.

                    {   // Fill the result image with correlation coefficient data
                        rcode = vicwin.correlateimages(ref simage, ref oimage, ref rimage);
                        if (rcode == vicwin.NO_ERROR)
                        {
                            int numelem;
                            string message;
                            double coef;
                            int rwidth = 0;
                            int rlength = 0;

                            rwidth = rimage.endx - rimage.stx + 1;
                            rlength = rimage.endy - rimage.sty + 1;
                            numelem = rwidth * rlength;
                            
                            // Allocate an array to hold the pixel data for the sorting
                            vicwin.COORD_VAL[] ptarray = new vicwin.COORD_VAL[numelem];
                            
                            // The pixel data in the result image will be sorted
                            // and placed in the array in descending order

                            rcode = vicwin.sortpixelsbyval(ref rimage, ref ptarray[0], numelem);
                            if (rcode == vicwin.NO_ERROR)
                            {
                                coef = (double)ptarray[0].val / 255.0;
                                if (coef > 1.0)
                                    coef = (double)ptarray[0].val / 65535.0;
                                message = "Highest correlation value: " + coef.ToString("0.0000");
                                message = message + "       Most probable location for mark: " + "  (" + ptarray[0].x + "," + ptarray[0].y + ")";
                                MsgBox(0, message, "Find mark", 0);
                            }
                        }
                        break;
                    }



Find a Mark - the Visual Basic Source Code

Requires Victor Image Processing Library for 32-bit Windows v 5.4 or higher and the helper dll vicstats.dll.
' Add the data type definition and function declarations to vicdef32.bas ...............................................

Type COORD_VAL
   val As Long
   x As Long
   y As Long
End Type

Public Declare Function correlationcoef Lib "vicstats.dll" (ByRef srcimg As imgdes, ByRef oprimg As imgdes, ByRef pCoef As Double) As Long
Public Declare Function correlateimages Lib "vicstats.dll" (ByRef srcimg As imgdes, ByRef oprimg As imgdes, ByRef resimg As imgdes) As Long
Public Declare Function calcavglevelfloat Lib "vicstats.dll" (ByRef srcimg As imgdes, ByRef redavg As Double, ByRef grnavg As Double, ByRef bluavg As Double) As Long
Public Declare Function sortpixelsbyval Lib "vicstats.dll" (ByRef srcimg As imgdes, ByRef first_elem As COORD_VAL, ByVal nelem As Long) As Long

' The Functions .................................................... 
Private Function findmark(srcimg As imgdes, oprimg As imgdes, resimg As imgdes, ptarray As COORD_VAL, numelem As Long) As Long
Dim rcode As Long

'   Fill the result image with correlation coefficient data
    rcode = correlateimages(srcimg, oprimg, resimg)
                                                      
   If (rcode = NO_ERROR) Then
        '  The pixel data in the result image will be sorted
        '  and placed in the array in descending order
       rcode = sortpixelsbyval(resimg, ptarray, numelem)

   End If
    
   findmark = rcode

End Function


Private Sub mnufindmark_Click()
Dim rcode As Long
Dim testimage As imgdes
Dim markimage As imgdes
Dim testfile As JpegData
Dim markfile As JpegData
Dim scols, srows, ocols, orows As Long

Dim ptarray() As COORD_VAL
Dim numelem As Long

   ' For easier understanding of the sample code no error checking is performed here
   ' but recognize that you should always test the return code to verify that each function is successful 
   rcode = jpeginfo("testc.jpg", testfile)
   rcode = allocimage(testimage, testfile.width, testfile.length, testfile.vbitcount)
   rcode = loadjpg("testc.jpg", testimage)

   rcode = jpeginfo("register.jpg", markfile)
   rcode = allocimage(markimage, markfile.width, markfile.length, markfile.vbitcount)
   rcode = loadjpg("register.jpg", markimage)

   scols = testimage.endx - testimage.stx + 1
   srows = testimage.endy - testimage.sty + 1
   ocols = markimage.endx - markimage.stx + 1
   orows = markimage.endy - markimage.sty + 1

   numelem = scols * srows

   ' Allocate an array to hold the pixel data for the sorting
   ReDim ptarray(0 To numelem - 1) As COORD_VAL
   
   rcode = findmark(testimage, markimage, testimage, ptarray(0), numelem)
   If (rcode = NO_ERROR) Then
      MsgBox ("Most probable location for mark: " & ptarray(0).val & "  (" & ptarray(0).x & "," & ptarray(0).y & ")")
   End If

   rcode = savejpg("testr.jpg", testimage, 50)
   freeimage markimage
   freeimage testimage

End Sub

Find a Mark - the C Source Code

Requires Victor Image Processing Library for 32-bit Windows v 5.4 or higher and the helper dll vicstats.dll.
// Add these declarations to vicdefs.h
typedef struct { unsigned val, x, y; } COORD_VAL;
int WINAPI correlationcoef(imgdes *srcimg, imgdes *oprimg, double *pCoef);
int WINAPI correlateimages(imgdes *srcimg, imgdes *oprimg, imgdes *resimg);
int WINAPI calcavglevelfloat(imgdes *srcimg, double *redavg, double *grnavg, double *bluavg);
int WINAPI sortpixelsbyval(imgdes *srcimg, COORD_VAL *darray, int nelem);

int findmark(imgdes *srcimg, imgdes *oprimg, imgdes *resimg, COORD_VAL *ptarray, int numelem)  
{
   int rcode;

   // Fills the result image with correlation coefficient data
   rcode = correlateimages(srcimg, oprimg, resimg); 
                                                      
   if(rcode == NO_ERROR) {
      // The pixel data in the result image will be sorted
      // and placed in the array in descending order
      rcode = sortpixelsbyval(resimg, ptarray, numelem);
      }
   return (rcode);
}

void DoMenuFindmark(HWND hWnd)
{
   int rcode;
   imgdes testimage;
   imgdes markimage;
   JpegData testfile;
   JpegData markfile;
   int scols, srows, ocols, orows;

   COORD_VAL *ptarray;
   int numelem;

   // For easier understanding of the sample code no error checking is performed here
   // but recognize that you should always test the return code to verify that each function is successful 
   rcode = jpeginfo("testc.jpg", &testfile);
   rcode = allocimage(&testimage, testfile.width, testfile.length, testfile.vbitcount);
   rcode = loadjpg("testc.jpg", &testimage);

   rcode = jpeginfo("register.jpg", &markfile);
   rcode = allocimage(&markimage, markfile.width, markfile.length, markfile.vbitcount);
   rcode = loadjpg("register.jpg", &markimage);

   scols = CALC_WIDTH(&testimage);
   srows = CALC_HEIGHT(&testimage);
   ocols = CALC_WIDTH(&markimage);
   orows = CALC_HEIGHT(&markimage);

   numelem =  scols * srows;

   // Allocate an array to hold the pixel data for the sorting
   ptarray = calloc(numelem, sizeof(COORD_VAL));
   rcode = findmark(&testimage, &markimage, &testimage, ptarray, numelem);
   if(rcode == NO_ERROR) {
      char szBuff[128];

      // Display the values for the four most likely locations
      wsprintf(szBuff, "Most probable locations for mark:"
         "\n%3d: (%3d, %3d)"
         "\n%3d: (%3d, %3d)"
         "\n%3d: (%3d, %3d)"
         "\n%3d: (%3d, %3d)",
          ptarray[0].val, ptarray[0].x, ptarray[0].y, 
          ptarray[1].val, ptarray[1].x, ptarray[1].y,
          ptarray[2].val, ptarray[2].x, ptarray[2].y,
          ptarray[3].val, ptarray[3].x, ptarray[3].y
          );
      MessageBox(hWnd, szBuff, szAppName, MB_OK);
      }

   if(ptarray)
      free(ptarray);

   savejpg("testr.jpg", &testimage, 50);
   freeimage(&markimage);
   freeimage(&testimage);
}

No comments:

Post a Comment