我正在尝试检测LCD屏幕上缺少的片段。想法是将这些片段与参考图像进行比较,并检测是否缺少任何片段。
这些是我的示例图片,
图片1:
图片2:
理想情况下,我正在寻找一种可以分辨出图像的哪个部分或哪个部分不正确的方法。
到目前为止我尝试过的,
这显然没有帮助。
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");
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;
}
代码
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;
}
我通过移动涂料中的屏幕区域直到它与参考图像重叠来制作了预期的结果图像。这是绝对差操作,
预期差异:
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;
答案 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");
对于您的图片,这给了我以下结果:
左右边界伪影来自平移。您可以根据需要将其切断。