Как удалить фон структурированного изображения в C#C#

Место общения программистов C#
Ответить
Anonymous
 Как удалить фон структурированного изображения в C#

Сообщение Anonymous »

Фотография квитанции содержит фон, например

Попробого, чтобы удалить фон, но фон не полностью удален:

Ответ в том, как удалить не равномерный фон из изображения описывает, как удалить фон, используя сценарии ImageMagick. Как удалить задним пластинком с помощью C# кода?using OpenCvSharp;
string imagePath = @"c:\a\krooningtaust.jpg";
Directory.CreateDirectory("out");
string ocrInputPath;
using Mat src = Cv2.ImRead(imagePath, ImreadModes.Color);
Mat pre = ReceiptPreproc.MakeOcrReady(src, useSauvola: true);
ocrInputPath = "out/ocr_ready.png";
Cv2.ImWrite(ocrInputPath, pre);
return 0;
< /code>
creciptpreproc class: < /p>
using OpenCvSharp;

public static class ReceiptPreproc
{
public static Mat MakeOcrReady(Mat src, bool useSauvola = true)
{
// 0) upscale for OCR
double scaleUp = 1.5;
Mat srcScaled = new();
Cv2.Resize(src, srcScaled, new Size(), scaleUp, scaleUp, InterpolationFlags.Cubic);

// 1) Warp (document detection)
Mat warped = WarpToTopDown(srcScaled);

Mat deskewed = warped;

// 3) Mask paper and paint outside white
Mat paper = MaskAndWhitenBackground(deskewed);

// 4) Illumination correction (divide normalization)
Mat gray = new();
Cv2.CvtColor(paper, gray, ColorConversionCodes.BGR2GRAY);
Mat bg = new();
Cv2.GaussianBlur(gray, bg, new Size(0, 0), 35);
Cv2.Max(bg, 1, bg);
Mat norm = new();
Cv2.Divide(gray, bg, norm, scale: 255);
Cv2.Normalize(norm, norm, 0, 255, NormTypes.MinMax);
norm.ConvertTo(norm, MatType.CV_8U);

// 5) Smooth background (bilateral) to keep edges
Mat smooth = new();
Cv2.BilateralFilter(norm, smooth, 9, 75, 75);

// 6) Binarize
Mat binary = useSauvola ? Sauvola(smooth, 41, 0.32, 128) : AdaptiveGaussian(smooth);

// 7) Small speckle removal
Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(2, 2));
Cv2.MorphologyEx(binary, binary, MorphTypes.Open, kernel);
return binary;
}

static Mat WarpToTopDown(Mat src)
{
double scale = 900.0 / Math.Max(src.Rows, src.Cols);
Mat small = new(); Cv2.Resize(src, small, new Size((int)(src.Cols * scale), (int)(src.Rows * scale)));
Mat gray = new(); Cv2.CvtColor(small, gray, ColorConversionCodes.BGR2GRAY);
Mat blur = new(); Cv2.GaussianBlur(gray, blur, new Size(5, 5), 0);
Mat edges = new(); Cv2.Canny(blur, edges, 50, 150);
Cv2.Dilate(edges, edges, Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3)));

Cv2.FindContours(edges, out Point[][]? contours, out _, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
contours = contours.OrderByDescending(cnt => Cv2.ContourArea(cnt)).ToArray();

Point2f[]? quad = null;
foreach (Point[]? cnt in contours.Take(10))
{
double peri = Cv2.ArcLength(cnt, true);
Point[] approx = Cv2.ApproxPolyDP(cnt, 0.02 * peri, true);
if (approx.Length == 4)
{
quad = approx.Select(p => new Point2f(p.X / (float)scale, p.Y / (float)scale)).ToArray();
break;
}
}

if (quad is null) return src;

Point2f[] ordered = OrderQuad(quad);
float widthA = Distance(ordered[2], ordered[3]);
float widthB = Distance(ordered[1], ordered[0]);
int maxW = (int)Math.Max(widthA, widthB);
float heightA = Distance(ordered[1], ordered[2]);
float heightB = Distance(ordered[0], ordered[3]);
int maxH = (int)Math.Max(heightA, heightB);

Point2f[] dst = new[] { new Point2f(0, 0), new Point2f(maxW - 1, 0), new Point2f(maxW - 1, maxH - 1), new Point2f(0, maxH - 1) };
Mat M = Cv2.GetPerspectiveTransform(ordered, dst);
Mat warped = new(); Cv2.WarpPerspective(src, warped, M, new Size(maxW, maxH));
return warped;
}

static Mat MaskAndWhitenBackground(Mat img)
{
Mat gray = new();
Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);
Mat blur = new();
Cv2.GaussianBlur(gray, blur, new Size(5, 5), 0);
Mat th = new();
Cv2.Threshold(blur, th, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
if (Cv2.Mean(th)[0] < 127) Cv2.BitwiseNot(th, th);

Mat mask = new();
Cv2.MorphologyEx(th, mask, MorphTypes.Close, Cv2.GetStructuringElement(MorphShapes.Rect, new Size(9, 9)));
Cv2.MorphologyEx(mask, mask, MorphTypes.Open, Cv2.GetStructuringElement(MorphShapes.Rect, new Size(5, 5)));

Mat paper = img.Clone();
paper.SetTo(new Scalar(255, 255, 255), ~mask);
return paper;
}

static Mat AdaptiveGaussian(Mat img)
{
Mat bin = new();
// Fix: Use AdaptiveThresholdTypes.GaussianC instead of AdaptiveThresholdTypes.Gaussian
Cv2.AdaptiveThreshold(img, bin, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, 51, 10);
return bin;
}

// Sauvola implementation using box filter mean and std
static Mat Sauvola(Mat img, int window, double k, double r)
{
Mat src32 = new(); img.ConvertTo(src32, MatType.CV_32F);
Mat mean = new(); Cv2.BoxFilter(src32, mean, -1, new Size(window, window));
Mat sqr = src32.Mul(src32);
Mat meanSqr = new(); Cv2.BoxFilter(sqr, meanSqr, -1, new Size(window, window));
Mat var = meanSqr - mean.Mul(mean);
Mat zero = new(var.Size(), var.Type(), Scalar.All(0));
Mat varNonNeg = new();
Cv2.Max(var, zero, varNonNeg);
Mat std = new();
Cv2.Sqrt(varNonNeg, std);

Mat stdDivR = new();
Cv2.Divide(std, r, stdDivR); // std/r
Mat stdDivRMinus1 = new();
Cv2.Subtract(stdDivR, 1.0, stdDivRMinus1); // (std/r) - 1.0
Mat kTimesStdDivRMinus1 = new();
Cv2.Multiply(stdDivRMinus1, k, kTimesStdDivRMinus1); // k * ((std/r) - 1.0)
Mat kTimesStdDivRMinus1TimesMean = new();
Cv2.Multiply(kTimesStdDivRMinus1, mean, kTimesStdDivRMinus1TimesMean); // k * ((std/r) - 1.0) * mean
Mat thresh = new();
Cv2.Add(mean, kTimesStdDivRMinus1TimesMean, thresh); // mean + k * ((std/r) - 1.0) * mean

Mat bin = new();
Cv2.Compare(src32, thresh, bin, CmpType.GT);
bin.ConvertTo(bin, MatType.CV_8U, 255);
return bin;
}

static Point2f[] OrderQuad(Point2f[] pts)
{
Point2f[] ordered = new Point2f[4];
float[] sum = pts.Select(p => p.X + p.Y).ToArray();
float[] diff = pts.Select(p => p.X - p.Y).ToArray();
ordered[0] = pts[Array.IndexOf(sum, sum.Min())]; // tl
ordered[2] = pts[Array.IndexOf(sum, sum.Max())]; // br
ordered[1] = pts[Array.IndexOf(diff, diff.Max())]; // tr
ordered[3] = pts[Array.IndexOf(diff, diff.Min())]; // bl
return ordered;
}
static float Distance(Point2f a, Point2f b) => (float)Math.Sqrt(Math.Pow(a.X - b.X, 2) + Math.Pow(a.Y - b.Y, 2));
}


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

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

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

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

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

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