631 lines
26 KiB
C#
631 lines
26 KiB
C#
using OpenCvSharp;
|
||
using OpenCvSharp.Flann;
|
||
using Sunny.UI.Win32;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using static System.Net.Mime.MediaTypeNames;
|
||
using Point = OpenCvSharp.Point;
|
||
using Size = OpenCvSharp.Size;
|
||
using System;
|
||
using OpenCvSharp;
|
||
using OpenCvSharp.Features2D;
|
||
using OpenCvSharp.Flann;
|
||
using System.Drawing;
|
||
|
||
namespace HisenceYoloDetection
|
||
{
|
||
public static class CheckDiffSciHelper
|
||
{
|
||
|
||
|
||
public static Mat ProcessImage(Mat image, Rect fillRect)
|
||
{
|
||
// 获取图像尺寸
|
||
int width = image.Width;
|
||
int height = image.Height;
|
||
|
||
// 定义左下角 30x30 矩形框
|
||
int rectSize = 30;
|
||
int rectX = 0;
|
||
int rectY = height - rectSize; // 确保是左下角
|
||
|
||
// 防止越界
|
||
if (rectY < 0 || rectX < 0 || rectSize > width || rectSize > height)
|
||
{
|
||
Console.WriteLine("图像尺寸不足以获取指定区域");
|
||
return image;
|
||
}
|
||
|
||
Rect roi = new Rect(rectX, rectY, rectSize, rectSize);
|
||
Mat roiMat = new Mat(image, roi);
|
||
|
||
// 计算平均颜色值
|
||
Scalar meanColor = Cv2.Mean(roiMat);
|
||
Vec3b fillColor = new Vec3b((byte)meanColor.Val0, (byte)meanColor.Val1, (byte)meanColor.Val2);
|
||
|
||
// 防止越界
|
||
if (fillRect.X < 0 || fillRect.Y < 0 || fillRect.X + fillRect.Width > width || fillRect.Y + fillRect.Height > height)
|
||
{
|
||
Console.WriteLine("填充区域超出图像范围");
|
||
return image;
|
||
}
|
||
|
||
// 填充指定区域
|
||
for (int y = fillRect.Y; y < fillRect.Y + fillRect.Height; y++)
|
||
{
|
||
for (int x = fillRect.X; x < fillRect.X + fillRect.Width; x++)
|
||
{
|
||
image.Set<Vec3b>(y, x, fillColor);
|
||
}
|
||
}
|
||
|
||
return image;
|
||
}
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="path1">标准图像</param>
|
||
/// <param name="path2">要对比的图像</param>
|
||
/// <param name="IfWhiteWord"> 白板黑字为true </param>
|
||
/// <param name="saveDir">存储路径</param>
|
||
public static bool CheckDiffSci(string path1, Mat MatDet, ref Mat ResultMat,Rect sqlrect, Rect detrect, bool IfWhiteWord, string saveDir)
|
||
{
|
||
// 读取和处理第一张图片。。
|
||
Mat img1 = Cv2.ImRead(path1, ImreadModes.Color);
|
||
if (img1.Empty())
|
||
{
|
||
Console.WriteLine($"Error loading image {path1}");
|
||
return false;
|
||
}
|
||
// Cv2.Resize(img1, img1, new Size(550, 270));
|
||
img1 = ProcessImage(img1, sqlrect);
|
||
Mat gimg1 = new Mat();
|
||
Cv2.CvtColor(img1, gimg1, ColorConversionCodes.BGR2GRAY);
|
||
Mat thr1 = new Mat();
|
||
|
||
if (IfWhiteWord)
|
||
{
|
||
Cv2.Threshold(gimg1, thr1, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);
|
||
}
|
||
else
|
||
{
|
||
Cv2.Threshold(gimg1, thr1, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
|
||
}
|
||
|
||
|
||
|
||
|
||
// 读取和处理第二张图片
|
||
Mat img2 = MatDet.Clone();
|
||
ResultMat= MatDet.Clone();
|
||
if (img2.Empty())
|
||
{
|
||
// Console.WriteLine($"Error loading image {path2}");
|
||
return false;
|
||
}
|
||
// Cv2.Resize(img2, img2, new Size(550, 270));
|
||
img2 = ProcessImage(img2, detrect);
|
||
Rect bottomleftRect= new Rect(0,img1.Height-30,30,30);
|
||
Scalar avgColor1 = Cv2.Mean(new Mat(img1,bottomleftRect));
|
||
Mat gimg2 = new Mat();
|
||
Cv2.CvtColor(img2, gimg2, ColorConversionCodes.BGR2GRAY);
|
||
Mat thr2 = new Mat();
|
||
//Cv2.Threshold(gimg2, thr2, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);
|
||
if (IfWhiteWord)
|
||
{
|
||
Cv2.Threshold(gimg2, thr2, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);
|
||
}
|
||
else
|
||
{
|
||
Cv2.Threshold(gimg2, thr2, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
|
||
}
|
||
|
||
|
||
//Rect area2 = new Rect(148,30,229,222);
|
||
sqlrect.Width += 20;
|
||
sqlrect.Height+= 100;
|
||
detrect.Width += 20;
|
||
detrect.Height+=100;
|
||
Mat matCutblack1 = new Mat(thr1, sqlrect);
|
||
|
||
if (IfWhiteWord)
|
||
{
|
||
matCutblack1.SetTo(Scalar.Black);
|
||
}
|
||
else
|
||
{
|
||
matCutblack1.SetTo(Scalar.Black);
|
||
}
|
||
Mat matCutblack2 = new Mat(thr2, detrect);
|
||
if (IfWhiteWord)
|
||
{
|
||
matCutblack2.SetTo(Scalar.Black);
|
||
}
|
||
else
|
||
{
|
||
matCutblack2.SetTo(Scalar.Black);
|
||
}
|
||
Cv2.Resize(thr1, thr1, new Size(550, 270));
|
||
Cv2.Resize(thr2, thr2, new Size(550, 270));
|
||
DateTime dt = DateTime.Now;
|
||
string filename = dt.Year.ToString() + dt.Month.ToString() + dt.Day.ToString() + dt.Hour.ToString() + dt.Minute.ToString() + dt.Millisecond.ToString();
|
||
|
||
// string savePath4 = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "_thr1.png");
|
||
// 保存结果
|
||
|
||
//Cv2.ImWrite(savePath4, thr1);
|
||
//string savePath3 = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "_thr2.png");
|
||
// 保存结果
|
||
|
||
//Cv2.ImWrite(savePath3, thr2);
|
||
|
||
// 创建卷积核
|
||
Mat filter1 = new Mat(15, 15, MatType.CV_32F, new Scalar(0));
|
||
filter1.Row(7).SetTo(new Scalar(0.025));
|
||
filter1.Col(7).SetTo(new Scalar(0.025));
|
||
|
||
// 应用卷积
|
||
Mat final_result1 = new Mat();
|
||
Cv2.Filter2D(thr1, final_result1, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
Cv2.Filter2D(final_result1, final_result1, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
Cv2.Filter2D(final_result1, final_result1, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
|
||
Mat final_result2 = new Mat();
|
||
Cv2.Filter2D(thr2, final_result2, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
Cv2.Filter2D(final_result2, final_result2, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
Cv2.Filter2D(final_result2, final_result2, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
//裁剪才行
|
||
|
||
|
||
//string savePath2 = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + "_final_result1.png");
|
||
////保存结果
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path2) + "_diff.png");
|
||
//Cv2.ImWrite(savePath2, final_result1);
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + "_final_result2.png");
|
||
////保存结果
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path2) + "_diff.png");
|
||
//Cv2.ImWrite(savePath, final_result2);
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
// 计算图像差异
|
||
Mat devIMG = new Mat();
|
||
Mat devIMG_ = new Mat();
|
||
Cv2.Subtract(final_result1, final_result2, devIMG);
|
||
Cv2.Subtract(final_result2, final_result1, devIMG_);
|
||
//string savePathd = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "devIMG.png");
|
||
//// 保存结果
|
||
|
||
//Cv2.ImWrite(savePathd, devIMG);
|
||
//string savePathd1 = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "devIMG_.png");
|
||
//// 保存结果
|
||
|
||
//Cv2.ImWrite(savePathd1, devIMG_);
|
||
// 对差异图像应用阈值
|
||
Cv2.Threshold(devIMG, devIMG, 20, 255, ThresholdTypes.Binary);
|
||
Cv2.Threshold(devIMG_, devIMG_, 20, 255, ThresholdTypes.Binary);
|
||
|
||
// 结合差异
|
||
Mat sumIMG = new Mat();
|
||
Cv2.Add(devIMG, devIMG_, sumIMG);
|
||
|
||
// 应用形态学操作
|
||
Mat kernelCL = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
|
||
Mat blackhatImg = new Mat();
|
||
Cv2.Dilate(sumIMG, blackhatImg, kernelCL);
|
||
|
||
// 处理轮廓和保存结果
|
||
Point[][] contours = new Point[10000][];
|
||
Cv2.FindContours(blackhatImg, out contours, out _, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);
|
||
bool isMatch = true;
|
||
foreach (var contour in contours)
|
||
{
|
||
if (Cv2.ContourArea(contour) <= 500)
|
||
{
|
||
Cv2.DrawContours(blackhatImg, new Point[][] { contour }, -1, Scalar.Black, thickness: Cv2.FILLED);
|
||
// 框选轮廓
|
||
//string savePath2 = Path.Combine("D:\\Hisence\\Test\\2\\ok", Path.GetFileNameWithoutExtension(path1) + filename + "_Rect.png");
|
||
// 保存结果
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path2) + "_diff.png");
|
||
//Cv2.ImWrite(savePath2, img2);
|
||
//string savePath = Path.Combine("D:\\Hisence\\Test\\2\\ok", Path.GetFileNameWithoutExtension(path1) + filename + "_diff.png");
|
||
// 保存结果
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path2) + "_diff.png");
|
||
// Cv2.ImWrite(savePath, blackhatImg);
|
||
}
|
||
else
|
||
{
|
||
Rect boundingRect = Cv2.BoundingRect(contour);
|
||
Cv2.Resize(img2, img2, new Size(550, 270));
|
||
Cv2.Rectangle(img2, boundingRect, Scalar.Red, thickness: 2);
|
||
isMatch = false;
|
||
string savePath2 = Path.Combine("D:\\Hisence\\Test\\2\\ng", Path.GetFileNameWithoutExtension(path1) + filename + "_Rect.png");
|
||
// 保存结果
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path2) + "_diff.png");
|
||
Cv2.ImWrite(savePath2, img2);
|
||
CheckDiffSciHelper1.ResizeImage(savePath2, savePath2, 640, 480, 75);
|
||
|
||
ResultMat = img2.Clone();
|
||
//string savePath = Path.Combine("D:\\Hisence\\Test\\2\\ng", Path.GetFileNameWithoutExtension(path1) + filename + "_diff.png");
|
||
// 保存结果
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path2) + "_diff.png");
|
||
//Cv2.ImWrite(savePath, blackhatImg);
|
||
}
|
||
}
|
||
|
||
// 新增的白色面积占比判断
|
||
double whiteArea1 = Cv2.CountNonZero(thr1);
|
||
double whiteArea2 = Cv2.CountNonZero(thr2);
|
||
double ratio1 = whiteArea1 / (thr1.Rows * thr1.Cols);
|
||
double ratio2 = whiteArea2 / (thr2.Rows * thr2.Cols);
|
||
|
||
if (Math.Abs(ratio1 - ratio2) >= 0.95)
|
||
{
|
||
isMatch = true;
|
||
}
|
||
|
||
return isMatch;
|
||
}
|
||
|
||
|
||
|
||
public static Rect strChangeRect(string strrect)
|
||
{
|
||
if (!string.IsNullOrEmpty(strrect))
|
||
{
|
||
string[] rectstr = strrect.Split(",");
|
||
int areaX = int.Parse(rectstr[0]);
|
||
int areaY = int.Parse(rectstr[1]);
|
||
int areaWidth = int.Parse(rectstr[2]);
|
||
int areaHeight = int.Parse(rectstr[3]);
|
||
|
||
Rect rect = new Rect(areaX, areaY, areaWidth, areaHeight);
|
||
return rect;
|
||
}
|
||
else
|
||
{
|
||
return new Rect(0, 0, 0, 0);
|
||
}
|
||
|
||
}
|
||
|
||
public static string rectChangeStr(Rect area)
|
||
{
|
||
string[] rectsql = new string[4];
|
||
rectsql[0] = Convert.ToString(area.X);
|
||
rectsql[1] = Convert.ToString(area.Y);
|
||
rectsql[2] = Convert.ToString(area.Width);
|
||
rectsql[3] = Convert.ToString(area.Height);
|
||
|
||
string strrect = rectsql.Join(",");
|
||
return strrect;
|
||
}
|
||
public static class CheckDiffSciHelper1
|
||
{
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="path1">标准图像</param>
|
||
/// <param name="path2">要对比的图像</param>
|
||
/// <param name="IfWhiteWord"> 白板黑字为true </param>
|
||
/// <param name="saveDir">存储路径</param>
|
||
public static bool CheckDiffSci(string path1, Mat MatDet, Rect sqlrect, Rect detrect, bool IfWhiteWord, string saveDir)
|
||
{
|
||
// 读取和处理第一张图片
|
||
Mat img1 = Cv2.ImRead(path1, ImreadModes.Color);
|
||
|
||
if (img1.Empty())
|
||
{
|
||
Console.WriteLine($"Error loading image {path1}");
|
||
return false;
|
||
}
|
||
// Cv2.Resize(img1, img1, new Size(550, 270));
|
||
img1 = RemoveBorders(img1);
|
||
Mat gimg1 = new Mat();
|
||
Cv2.CvtColor(img1, gimg1, ColorConversionCodes.BGR2GRAY);
|
||
Mat thr1 = new Mat();
|
||
|
||
if (IfWhiteWord)
|
||
{
|
||
Cv2.Threshold(gimg1, thr1, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);
|
||
}
|
||
else
|
||
{
|
||
Cv2.Threshold(gimg1, thr1, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
|
||
}
|
||
|
||
|
||
|
||
|
||
// 读取和处理第二张图片
|
||
Mat img2 = MatDet.Clone();
|
||
if (img2.Empty())
|
||
{
|
||
// Console.WriteLine($"Error loading image {path2}");
|
||
return false;
|
||
}
|
||
// Cv2.Resize(img2, img2, new Size(550, 270));
|
||
img2 = RemoveBorders(img2);
|
||
Mat gimg2 = new Mat();
|
||
Cv2.CvtColor(img2, gimg2, ColorConversionCodes.BGR2GRAY);
|
||
Mat thr2 = new Mat();
|
||
//Cv2.Threshold(gimg2, thr2, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);
|
||
if (IfWhiteWord)
|
||
{
|
||
Cv2.Threshold(gimg2, thr2, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);
|
||
}
|
||
else
|
||
{
|
||
Cv2.Threshold(gimg2, thr2, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
|
||
}
|
||
|
||
|
||
//Rect area2 = new Rect(148,30,229,222);
|
||
sqlrect.Width += 20;
|
||
sqlrect.Height += 20;
|
||
detrect.Width += 20;
|
||
detrect.Height += 20;
|
||
Mat matCutblack1 = new Mat(thr1, sqlrect);
|
||
if (IfWhiteWord)
|
||
{
|
||
matCutblack1.SetTo(Scalar.Black);
|
||
}
|
||
else
|
||
{
|
||
matCutblack1.SetTo(Scalar.Black);
|
||
}
|
||
Mat matCutblack2 = new Mat(thr2, detrect);
|
||
if (IfWhiteWord)
|
||
{
|
||
matCutblack2.SetTo(Scalar.Black);
|
||
}
|
||
else
|
||
{
|
||
matCutblack2.SetTo(Scalar.Black);
|
||
}
|
||
Cv2.Resize(thr1, thr1, new Size(845, 498));
|
||
Cv2.Resize(thr2, thr2, new Size(845, 498));
|
||
DateTime dt = DateTime.Now;
|
||
string filename = dt.Year.ToString() + dt.Month.ToString() + dt.Day.ToString() + dt.Hour.ToString() + dt.Minute.ToString() + dt.Millisecond.ToString();
|
||
|
||
//string savePath4 = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "_thr1.png");
|
||
// 保存结果
|
||
|
||
//Cv2.ImWrite(savePath4, thr1);
|
||
// string savePath3 = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "_thr2.png");
|
||
// 保存结果
|
||
|
||
// Cv2.ImWrite(savePath3, thr2);
|
||
|
||
// 创建卷积核
|
||
|
||
Mat filter1 = new Mat(15, 15, MatType.CV_32F, new Scalar(0));
|
||
filter1.Row(7).SetTo(new Scalar(0.025));
|
||
filter1.Col(7).SetTo(new Scalar(0.025));
|
||
|
||
|
||
|
||
// 应用卷积
|
||
Mat final_result1 = new Mat();
|
||
Cv2.Filter2D(thr1, final_result1, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
Cv2.Filter2D(final_result1, final_result1, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
Cv2.Filter2D(final_result1, final_result1, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
|
||
//Cv2.Filter2D(final_result1, final_result1, -1, filter2, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
|
||
Mat final_result2 = new Mat();
|
||
Cv2.Filter2D(thr2, final_result2, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
Cv2.Filter2D(final_result2, final_result2, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
Cv2.Filter2D(final_result2, final_result2, -1, filter1, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
|
||
//Cv2.Filter2D(final_result2, final_result2, -1, filter2, anchor: new Point(-1, -1), 0, BorderTypes.Reflect);
|
||
//裁剪才行
|
||
|
||
|
||
//string savePath2 = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + "_final_result1.png");
|
||
//// 保存结果
|
||
////string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path2) + "_diff.png");
|
||
//Cv2.ImWrite(savePath2, final_result1);
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + "_final_result2.png");
|
||
//// 保存结果
|
||
////string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path2) + "_diff.png");
|
||
//Cv2.ImWrite(savePath, final_result2);
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
// 计算图像差异
|
||
Mat devIMG = new Mat();
|
||
Mat devIMG_ = new Mat();
|
||
Cv2.Subtract(final_result1, final_result2, devIMG);
|
||
Cv2.Subtract(final_result2, final_result1, devIMG_);
|
||
//string savePathd = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "devIMG.png");
|
||
// 保存结果
|
||
|
||
// Cv2.ImWrite(savePathd, devIMG);
|
||
//string savePathd1 = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "devIMG_.png");
|
||
// 保存结果
|
||
|
||
//Cv2.ImWrite(savePathd1, devIMG_);
|
||
// 对差异图像应用阈值
|
||
Cv2.Threshold(devIMG, devIMG, 8, 255, ThresholdTypes.Binary);
|
||
Cv2.Threshold(devIMG_, devIMG_, 8, 255, ThresholdTypes.Binary);
|
||
|
||
// 结合差异
|
||
Mat sumIMG = new Mat();
|
||
Cv2.Add(devIMG, devIMG_, sumIMG);
|
||
//string savePaths = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "sumIMG.png");
|
||
// 保存结果
|
||
|
||
//Cv2.ImWrite(savePaths, sumIMG);
|
||
// 应用形态学操作
|
||
Mat kernelCL = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
|
||
Mat blackhatImg = new Mat();
|
||
Cv2.Dilate(sumIMG, blackhatImg, kernelCL);
|
||
|
||
// 处理轮廓和保存结果
|
||
Point[][] contours = new Point[10000][];
|
||
Cv2.FindContours(blackhatImg, out contours, out _, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);
|
||
bool isMatch = true;
|
||
foreach (var contour in contours)
|
||
{
|
||
if (Cv2.ContourArea(contour) <= 500)
|
||
{
|
||
Cv2.DrawContours(blackhatImg, new Point[][] { contour }, -1, Scalar.Black, thickness: Cv2.FILLED);
|
||
// 框选轮廓
|
||
|
||
}
|
||
else
|
||
{
|
||
Rect boundingRect = Cv2.BoundingRect(contour);
|
||
Cv2.Rectangle(img2, boundingRect, Scalar.Red, thickness: 2);
|
||
isMatch = false;
|
||
}
|
||
}
|
||
|
||
string savePath2 = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "_Rect.png");
|
||
// 保存结果
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path2) + "_diff.png");
|
||
Cv2.ImWrite(savePath2, img2);
|
||
ResizeImage(savePath2, savePath2, 640, 480, 75);
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path1) + filename + "_diff.png");
|
||
// 保存结果
|
||
//string savePath = Path.Combine(saveDir, Path.GetFileNameWithoutExtension(path2) + "_diff.png");
|
||
//Cv2.ImWrite(savePath, blackhatImg);
|
||
return isMatch;
|
||
}
|
||
|
||
public static void ResizeImage(string inputPath, string outputPath, int newWidth, int newHeight, int quality)
|
||
{
|
||
// 加载原始图像
|
||
using (Mat originalImage = Cv2.ImRead(inputPath))
|
||
{
|
||
// 创建一个Mat对象用于存储缩放后的图像
|
||
using (Mat resizedImage = new Mat())
|
||
{
|
||
// 缩放图像
|
||
Cv2.Resize(originalImage, resizedImage, new OpenCvSharp.Size(newWidth, newHeight));
|
||
|
||
// 保存图像为JPEG格式,并设置压缩质量
|
||
SaveJpeg(outputPath, resizedImage, quality);
|
||
Console.WriteLine($"Image saved to {outputPath}");
|
||
}
|
||
}
|
||
}
|
||
|
||
static void SaveJpeg(string path, Mat image, int quality)
|
||
{
|
||
// 设置JPEG编码参数
|
||
var encodeParams = new[] { new ImageEncodingParam(ImwriteFlags.JpegQuality, quality) };
|
||
|
||
// 保存图像
|
||
Cv2.ImWrite(path, image, encodeParams);
|
||
}
|
||
static Mat RemoveBorders(Mat image)
|
||
{
|
||
// 将图像转换为灰度图
|
||
Mat grayImage = new Mat();
|
||
Cv2.CvtColor(image, grayImage, ColorConversionCodes.BGR2GRAY);
|
||
|
||
// 使用自适应二值化将图像变为黑白图
|
||
Mat binaryImage = new Mat();
|
||
Cv2.AdaptiveThreshold(grayImage, binaryImage, 255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 11, 2);
|
||
|
||
// 反转颜色
|
||
Mat invertedBinaryImage = new Mat();
|
||
Cv2.BitwiseNot(binaryImage, invertedBinaryImage);
|
||
|
||
// 查找轮廓
|
||
Point[][] contours;
|
||
HierarchyIndex[] hierarchy;
|
||
Cv2.FindContours(invertedBinaryImage, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
|
||
|
||
// 找到包含最大面积的轮廓
|
||
double maxArea = 0;
|
||
Point[] maxContour = null;
|
||
foreach (var contour in contours)
|
||
{
|
||
double area = Cv2.ContourArea(contour);
|
||
if (area > maxArea)
|
||
{
|
||
maxArea = area;
|
||
maxContour = contour;
|
||
}
|
||
}
|
||
|
||
if (maxContour == null)
|
||
{
|
||
Console.WriteLine("未找到有效轮廓!");
|
||
return image;
|
||
}
|
||
|
||
// 找到平行四边形的四个顶点
|
||
Point[] approx = Cv2.ApproxPolyDP(maxContour, Cv2.ArcLength(maxContour, true) * 0.02, true);
|
||
Point2f[] srcPoints = approx.Select(p => new Point2f(p.X, p.Y)).ToArray();
|
||
|
||
if (srcPoints.Length != 4)
|
||
{
|
||
Console.WriteLine("未找到平行四边形的四个顶点!");
|
||
return image;
|
||
}
|
||
|
||
// 按顺时针顺序对顶点进行排序
|
||
srcPoints = OrderPoints(srcPoints);
|
||
|
||
// 确定目标图像的四个顶点
|
||
Point2f[] dstPoints = new Point2f[]
|
||
{
|
||
new Point2f(0, 0),
|
||
new Point2f(image.Width - 1, 0),
|
||
new Point2f(image.Width - 1, image.Height - 1),
|
||
new Point2f(0, image.Height - 1)
|
||
};
|
||
|
||
// 计算透视变换矩阵
|
||
Mat transformMatrix = Cv2.GetPerspectiveTransform(srcPoints, dstPoints);
|
||
|
||
// 应用透视变换
|
||
Mat warpedImage = new Mat();
|
||
Cv2.WarpPerspective(image, warpedImage, transformMatrix, new Size(image.Width, image.Height));
|
||
|
||
return warpedImage;
|
||
}
|
||
|
||
private static Point2f[] OrderPoints(Point2f[] points)
|
||
{
|
||
// 对顶点进行排序,顺时针顺序
|
||
Point2f[] orderedPoints = new Point2f[4];
|
||
|
||
// 计算质心
|
||
Point2f center = new Point2f(points.Average(p => p.X), points.Average(p => p.Y));
|
||
|
||
foreach (var point in points)
|
||
{
|
||
if (point.X < center.X && point.Y < center.Y)
|
||
orderedPoints[0] = point; // 左上
|
||
else if (point.X > center.X && point.Y < center.Y)
|
||
orderedPoints[1] = point; // 右上
|
||
else if (point.X > center.X && point.Y > center.Y)
|
||
orderedPoints[2] = point; // 右下
|
||
else if (point.X < center.X && point.Y > center.Y)
|
||
orderedPoints[3] = point; // 左下
|
||
}
|
||
|
||
return orderedPoints;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|