如何检测两个相似但未对齐的图像中的缺陷?

时间:2019-09-17 15:57:15

标签: opencv image-processing emgucv

我正在尝试检测LCD屏幕上缺少的片段。想法是将这些片段与参考图像进行比较,并检测是否缺少任何片段。

这些是我的示例图片,

图片1:

image1

图片2:

image2

理想情况下,我正在寻找一种可以分辨出图像的哪个部分或哪个部分不正确的方法。

到目前为止我尝试过的,

  1. 绝对差 请注意,由于上面的两个图像略有对齐, 取两个图像的绝对差返回此 image difference

这显然没有帮助。

EmguCV中的代码

Image<Gray, byte> im1 = new Image<Gray, byte>(@"E:\code\misalign_detect\im1.bmp");
Image<Gray, byte> im2 = new Image<Gray, byte>(@"E:\code\misalign_detect\im2.bmp");

CvInvoke.AbsDiff(im1, im2, im2);
im2.Save($"im1im2 difference.bmp");
    直方图比较和欧氏距离 对于这两个图像,它似乎起作用。直方图比较指标返回0.93,这可能是确定的,足以使它们不同。但是,

A。没告诉我差异在哪里
B.当图像之间只有几个部分不同时,分数表现不佳

代码

private double ImageComparision(Mat testImage, Mat refImage)
{
      double retStatus = 0.0f;
      double m_total = 0.0f;
      try
      {
          //Create four ROI of test image
          List<DenseHistogram> m_testROIHisto = MakeFourROIofImage(testImage.ToImage<Gray, Byte>());

          //Create four ROI of reference image
          List<DenseHistogram> m_ReferenceROIHisto = MakeFourROIofImage(refImage.ToImage<Gray, Byte>());


          for (int i = 0; i < 4; i++)
          {
              DenseHistogram hist_test1 = m_testROIHisto[i];
              DenseHistogram hist_test2 = m_ReferenceROIHisto[i];
              double cBlue = CvInvoke.CompareHist(hist_test1, hist_test2, HistogramCompMethod.Correl);

              m_total += cBlue;
          }
      }
      catch (Exception ex)
      {
          MessageBox.Show("Exception in ImageComparision() " + ex.ToString());
      }

      retStatus = m_total / 4;

      return retStatus;
}

/// <summary>
/// Function used to make Four ROI of Image
/// Then compute Histogram of each ROI
/// </summary>
private List<DenseHistogram> MakeFourROIofImage(Image<Gray, Byte> img)
{
      int m_height = img.Height;
      int m_width = img.Width;
      List<DenseHistogram> m_imgList = new List<DenseHistogram>();
      for (int i = 0; i < m_width;)
      {
          for (int j = 0; j < m_height;)
          {
              img.ROI = new Rectangle(i, j, (m_width / 2), (m_height / 2));
              //cv::Mat m_roiImg = img(rectangle);
              Image<Gray, Byte> m_roiImg = img.Copy();

              // Create and initialize histogram
              DenseHistogram hist = new DenseHistogram(256, new RangeF(0.0f, 255.0f));

              // Histogram Computing
              hist.Calculate<Byte>(new Image<Gray, byte>[] { m_roiImg }, true, null);
              m_imgList.Add(hist);

              j += (m_height / 2);
          }
          i += (m_width / 2);
      }
      return m_imgList;
}

  1. 模板匹配 我目前正在遵循一种粗略的方法,即从参考图像中裁剪每个数字,然后尝试在当前图像中找到与它的良好匹配。 opencv MatchTemplate()函数是平移不变的,但不是旋转不变的-因此,当LCD屏幕由于物理变化而略微旋转时,它通常会失败。

代码

private Point GetBestImageMatch(Image<Gray, Byte> grayimg, Image<Gray, Byte> templateimg, double thresh = 0.8)
{
      grayimg = grayimg;
      templateimg = templateimg;

      int rcols = grayimg.Cols - templateimg.Cols + 1;
      int rrows = grayimg.Rows - templateimg.Rows + 1;
      Image<Gray, float> result = new Image<Gray, float>(rrows, rcols);

      // perform matching
      CvInvoke.MatchTemplate(grayimg, templateimg, result, Emgu.CV.CvEnum.TemplateMatchingType.CcoeffNormed);

      // check results
      double minv = 0, maxv = 0;
      Point minLoc = new Point(), maxLoc = new Point();
      CvInvoke.MinMaxLoc(result, ref minv, ref maxv, ref minLoc, ref maxLoc);

      if(maxv < thresh)
      {
          return new Point(-1, -1);
      }

      return maxLoc;
}

我通过移动涂料中的屏幕区域直到它与参考图像重叠来制作了预期的结果图像。这是绝对差操作,

预期差异:

expected_difference of Image1 and Image2

Edit1:

Hans建议我应该尝试图像注册,我认为他的意思是this,我想mapAffine可能会有所帮助。但是,我找不到mapShift或mapAffine的教程。相反,我发现了这个-Image Alignment in OpenCV

我已经在下面的EmguCV中重写了代码,但是它在Exception thrown: 'Emgu.CV.Util.CvException' in Emgu.CV.World.dll处抛出了FindTransformECC()。我不确定为什么

Mat im1 = new Image<Gray, byte>(@"E:\code\panel1.bmp").Mat;
Mat im2 = new Image<Gray, byte>(@"E:\code\panel1_shifted.bmp").Mat;

MotionType wrapMode = MotionType.Euclidean;
Mat warp_matrix = Mat.Eye(2, 3, DepthType.Cv32F, 1);
int number_of_iterations = 5000;
double termination_eps = 1e-10;
MCvTermCriteria criteria = new MCvTermCriteria(number_of_iterations, termination_eps);
CvInvoke.FindTransformECC(im1, im2, warp_matrix, wrapMode, criteria);

Mat im2_aligned = new Image<Gray, byte>(im1.Size).Mat;
CvInvoke.WarpPerspective(im2, im2, warp_matrix, im1.Size, Inter.Linear);
myPicBox.Image = im2.Bitmap;

1 个答案:

答案 0 :(得分:1)

只要图像只有平移,就可以使用PhaseCorrelation使用EmguCV非常简单地执行图像配准。

pathToImg1 是您的第一个示例图像, pathToImg2 是您的第二个示例图像。

    //load images
    var m1 = new Mat(<pathToImg1>, ImreadModes.Grayscale);
    var m2 = new Mat(<pathToImg2>, ImreadModes.Grayscale);
    
    //Convert depth to be processible by phase correlation function
    var m3 = new Mat();
    var m4 = new Mat();
    m1.ConvertTo(m3, DepthType.Cv32F);
    m2.ConvertTo(m4, DepthType.Cv32F);
    
    //Detect translation
    MCvPoint2D64f shift = CvInvoke.PhaseCorrelate(m3, m4, null, out _);
    
    //Setup affine transformation matrix
    var translateTransform = new Matrix<float>(2, 3)
    {
        [0, 0] = 1.0f,
        [1, 1] = 1.0f,
        [0, 2] = Convert.ToSingle(shift.X),
        [1, 2] = Convert.ToSingle(shift.Y)
    };
    
    //Translate image1
    CvInvoke.WarpAffine(m1, m1, translateTransform, m1.Size, Inter.Area);
    
    //Get diff
    CvInvoke.AbsDiff(m1, m2, m2);
    
    
    m2.Save(<outPath>\result.png");

对于您的图片,这给了我以下结果:

enter image description here

左右边界伪影来自平移。您可以根据需要将其切断。