【问题标题】:How do I detect defects in two similar but misaligned images?如何检测两个相似但未对齐的图像中的缺陷?
【发布时间】:2020-01-18 12:55:21
【问题描述】:

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

这些是我的示例图片,

图片1:

图 2:

理想情况下,我正在寻找一种方法来判断图像的哪个部分或哪个片段不正确。

到目前为止我已经尝试过,

  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");
  1. 直方图比较和欧几里得距离 对于这两个图像,它似乎有效。直方图比较指标返回 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;
}

我通过在绘画中移动屏幕区域直到它与参考图像重叠来制作预期的结果图像。这是之后的绝对差分运算,

预期差异:

编辑1:

Hans 建议我应该尝试 Image Registration,我认为他的意思是 this,我猜 mapAffine 会有些相关。但是,我找不到 mapShift 或 mapAffine 的教程。相反,我发现了这个 - Image Alignment in OpenCV

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

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;

【问题讨论】:

  • [...] 通过在绘图中移动屏幕区域直到它与参考图像重叠。 这称为image registration(或有时称为图像对齐)。有很多关于该主题的 OpenCV 教程。
  • @HansHirse 好吧,我已经添加了另一个尝试,我在网上找到了一个图像对齐教程。但它没有编译,你能看看我做错了什么吗?
  • 我从未与 EmguCV 合作过,所以我无法为您提供帮助,抱歉。

标签: opencv image-processing emgucv


【解决方案1】:

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

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");

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

左边框和下边框伪影来自平移移位。如果你需要,你可以把它剪掉。

【讨论】:

    猜你喜欢
    • 2019-06-22
    • 2011-09-18
    • 2011-06-03
    • 1970-01-01
    • 2014-10-06
    • 2016-08-10
    • 2014-10-03
    • 2017-10-09
    • 2020-05-02
    相关资源
    最近更新 更多