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

问题描述 投票:2回答:1

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

这些是我的示例图像,

图片1:

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLmltZ3VyLmNvbS9yRXF1TVd6LnBuZyJ9” alt =“ image1”>

图片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;
}

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

预期差异:

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLmltZ3VyLmNvbS9BSVFLaTkwLnBuZyJ9” alt =“与Image1和Image2的预期差异”>

编辑1:

[Han建议我应该尝试图像配准,我认为他的意思是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;
opencv image-processing emgucv
1个回答
0
投票

只要您的图像只有平移,您就可以使用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

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

© www.soinside.com 2019 - 2024. All rights reserved.