Сравнение снимков экрана с OpenCV и C# .NETC#

Место общения программистов C#
Ответить
Anonymous
 Сравнение снимков экрана с OpenCV и C# .NET

Сообщение Anonymous »

Я работаю над решением, которое позволит улучшить сравнение скриншотов наших компаний. В настоящее время мы наблюдаем множество сбоев из-за различий в пикселях и т. д. Я реализовал решение в OpenCvSharp, которое работает на 90%. Однако некоторые изображения, похоже, дают ложные срабатывания, рисуя контуры (красные рамки) вокруг вещей, которые не изменились. Кажется, это несколько случайно и не связано с каким-либо конкретным типом изображения. Подробности смотрите на изображениях ниже (не обращайте внимания на поля в верхнем левом и правом углах, я сделал это, чтобы скрыть информацию о конкретной компании)
Базовый файл:
Изображение

Файл различий (после сравнения выполнено) см. маленькую красную рамку вокруг данные графика:
Изображение

Эта работа направлена ​​на то, чтобы избежать проблем, описанных ниже, но после почти двух недель разработки и настройки кода у меня начинают заканчиваться идеи. Код, который я сейчас использую, приведен ниже со следующими параметрами:
1. baselinePath -> This is simply the path to the baseline image
2. currentImageScreenshot - The current screenshot to compare against baseline
3. testName -> string containing a test name for debugging and logging purposes
4. imageConfig -> Object containing threshold values

public static void CompareImagesForDifferences(string baselineImagePath, Screenshot currentImageScreenshot, string testName, ImageComparisonConfig imageConfig)
{
string currentImagePath = SaveCurrentImage(currentImageScreenshot, testName, imageConfig);
Mat baselineImage = LoadImage(baselineImagePath);
Mat currentImage = LoadImage(currentImagePath);

ResizeImage(baselineImage, currentImage);

Mat baselineGray = ConvertToGrayscale(baselineImage);
Mat currentGray = ConvertToGrayscale(currentImage);

double ssimScore = ComputeSSIM(baselineGray, currentGray, out Mat ssimMap);

if (ssimScore >= double.Parse(imageConfig.GetSSIMThresholdSetting()))
{
// Images are identical
Logger.Info("Images are similar. No significant differences detected.");
return;
}

if (isSignificantChangesBetweenImages(baselineImage, currentImage, ssimMap, imageConfig, out Mat filledImage))
{
string diffImagePath = $@"{imageConfig.GetFailuresPath()}\\{testName}_Diff.png";
SaveDiffImage(filledImage, testName, imageConfig, diffImagePath, baselineImagePath);
}
}

В коде ниже кроется проблема. Здесь рассчитываются различия. Метод принимает 2 объекта Mat, содержащие базовое и новое изображение, а также ssimMap и конфигурацию.
private static bool isSignificantChangesBetweenImages(Mat baselineImage, Mat currentImage, Mat ssimMap, ImageComparisonConfig imageConfig, out Mat filledImage)
{
filledImage = currentImage.Clone();
Mat diff = new Mat();
ssimMap.ConvertTo(diff, MatType.CV_8UC1, 255);

Mat thresh = new Mat();
Cv2.Threshold(diff, thresh, 0, 255, ThresholdTypes.BinaryInv | ThresholdTypes.Otsu);

Point[][] contourDifferencePoints;
HierarchyIndex[] hierarchyIndex;
Cv2.FindContours(thresh, out contourDifferencePoints, out hierarchyIndex, RetrievalModes.List, ContourApproximationModes.ApproxSimple);

return DrawSignificantChanges(baselineImage, contourDifferencePoints, imageConfig, filledImage);
}

Приведенный ниже метод затем нарисует точки контура (если таковые имеются). Я считаю, что что-то внутри этого кода создает ложные срабатывания. Я добавил сюда некоторый код, чтобы игнорировать любые изменения вокруг границы изображения, поскольку обычно для этого конкретного приложения никаких изменений вокруг границы не происходит. В настоящее время для imageConfig.GetPixelToleranceSetting() установлено значение 10. Следующим моим предположением было бы увеличить это число до 15 или 20
private static bool DrawSignificantChanges(Mat baselineImage, Point[][] contours, ImageComparisonConfig imageConfig, Mat filledImage, double minAreaRatio = 0.0001, double maxAreaRatio = 0.1)
{
bool hasSignificantChanges = false;
double totalImageArea = baselineImage.Width * baselineImage.Height;
double minArea = totalImageArea * minAreaRatio;
double maxArea = totalImageArea * maxAreaRatio;

foreach (var contour in contours)
{
double area = Cv2.ContourArea(contour);
if (area < minArea || area > maxArea) continue;

Rect boundingRect = Cv2.BoundingRect(contour);

// Ignore changes near the image border
int borderThreshold = 5;
if (boundingRect.X = baselineImage.Height - borderThreshold)
{
continue;
}

// Check if the difference is significant enough
using (Mat roi = new Mat(baselineImage, boundingRect))
{
Scalar mean = Cv2.Mean(roi);
if (mean.Val0 < int.Parse(imageConfig.GetPixelToleranceSetting())) // Adjust this threshold as needed
{
continue;
}
}

// Draw Rectangle shape in red around the differences
Cv2.Rectangle(filledImage, boundingRect, new Scalar(0, 0, 255), 2);
hasSignificantChanges = true;
}
return hasSignificantChanges;
}

Наконец, метод ComputeSSIM (я взял его из сообщения, написанного на Python и преобразованного в CSharp)
public static double StructuralSimilarityIndex(Mat img1, Mat img2, out Mat diff)
{
const double K1 = 0.01;
const double K2 = 0.03;
const double L = 255;

// Constants for SSIM calculation
double c1 = Math.Pow(K1 * L, 2);
double c2 = Math.Pow(K2 * L, 2);

// Convert images to floating point
using var f1 = new Mat();
using var f2 = new Mat();
img1.ConvertTo(f1, MatType.CV_32F);
img2.ConvertTo(f2, MatType.CV_32F);

// Compute means
using var mu1 = new Mat();
using var mu2 = new Mat();
Cv2.GaussianBlur(f1, mu1, new Size(11, 11), 1.5);
Cv2.GaussianBlur(f2, mu2, new Size(11, 11), 1.5);

// Compute squares
using var mu1Sq = mu1.Mul(mu1);
using var mu2Sq = mu2.Mul(mu2);
using var mu1Mu2 = mu1.Mul(mu2);

// Compute variances and covariance
using var temp1 = new Mat();
using var temp2 = new Mat();
using var sigma1Sq = new Mat();
using var sigma2Sq = new Mat();
using var sigma12 = new Mat();

Cv2.GaussianBlur(f1.Mul(f1), temp1, new Size(11, 11), 1.5);
Cv2.GaussianBlur(f2.Mul(f2), temp2, new Size(11, 11), 1.5);

Cv2.Subtract(temp1, mu1Sq, sigma1Sq);
Cv2.Subtract(temp2, mu2Sq, sigma2Sq);

Cv2.GaussianBlur(f1.Mul(f2), sigma12, new Size(11, 11), 1.5);
Cv2.Subtract(sigma12, mu1Mu2, sigma12);

// Compute SSIM
using var numerator1 = new Mat();
using var numerator2 = new Mat();
using var denominator1 = new Mat();
using var denominator2 = new Mat();

Cv2.Multiply(mu1Mu2, 2, numerator1);
Cv2.Add(numerator1, Scalar.All(c1), numerator1);

Cv2.Multiply(sigma12, 2, numerator2);
Cv2.Add(numerator2, Scalar.All(c2), numerator2);

Cv2.Add(mu1Sq, mu2Sq, denominator1);
Cv2.Add(denominator1, Scalar.All(c1), denominator1);

Cv2.Add(sigma1Sq, sigma2Sq, denominator2);
Cv2.Add(denominator2, Scalar.All(c2), denominator2);

using var ssimMap = new Mat();
using var temp = new Mat();

Cv2.Multiply(numerator1, numerator2, temp);
Cv2.Multiply(denominator1, denominator2, ssimMap);
Cv2.Divide(temp, ssimMap, ssimMap);

// Calculate mean SSIM
var mssim = Cv2.Mean(ssimMap);

// Calculate difference map for visualization
diff = new Mat();
Cv2.Absdiff(img1, img2, diff);
Cv2.Normalize(diff, diff, 0, 255, NormTypes.MinMax);
diff.ConvertTo(diff, MatType.CV_8UC1);

return mssim.Val0;
}


Подробнее здесь: https://stackoverflow.com/questions/791 ... -sharp-net
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»