Anonymous
Как найти печатный документ на изображении
Сообщение
Anonymous » 27 сен 2025, 21:56
Изображение содержит отдельный документ, напечатанный в белой бумаге. Background of image can be different.
Tried to get document using code from
https://scanbot.io/techblog/document-ed ... th-opencv/ with OpenCvsharp (
https://github.com/shimat/opencvsharp ) by finding biggest rectangle using C# code
Код: Выделить всё
using Mat src = Cv2.ImRead("myimage.jpg", ImreadModes.Color);
var result = WarpToTopDown(src);
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 blurred = new();
Cv2.GaussianBlur(gray,blurred,new Size(5,5),0);
Mat edges = new();
Cv2.Canny(blurred,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))];
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) {
thow new Exception("no document");
}
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 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 Point2f[] OrderQuad(Point2f[] pts) {
Point2f[] ordered = new Point2f[4];
float[] sum = [.. pts.Select(p => p.X + p.Y)];
float[] diff = [.. pts.Select(p => p.X - p.Y)];
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));
< /code>
Но это возвращает целое изображение. В Foreach Check < /p>
if(approx.Length == 4) {
Если true для первого контура, который является целым изображением и, следовательно, возвращается целое изображение.
для изображения
Подробнее здесь:
https://stackoverflow.com/questions/797 ... t-in-image
1758999377
Anonymous
Изображение содержит отдельный документ, напечатанный в белой бумаге. Background of image can be different. Tried to get document using code from https://scanbot.io/techblog/document-edge-detection-with-opencv/ with OpenCvsharp (https://github.com/shimat/opencvsharp) by finding biggest rectangle using C# code [code] using Mat src = Cv2.ImRead("myimage.jpg", ImreadModes.Color); var result = WarpToTopDown(src); 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 blurred = new(); Cv2.GaussianBlur(gray,blurred,new Size(5,5),0); Mat edges = new(); Cv2.Canny(blurred,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))]; 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) { thow new Exception("no document"); } 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 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 Point2f[] OrderQuad(Point2f[] pts) { Point2f[] ordered = new Point2f[4]; float[] sum = [.. pts.Select(p => p.X + p.Y)]; float[] diff = [.. pts.Select(p => p.X - p.Y)]; 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)); < /code> Но это возвращает целое изображение. В Foreach Check < /p> if(approx.Length == 4) { [/code] Если true для первого контура, который является целым изображением и, следовательно, возвращается целое изображение. для изображения Подробнее здесь: [url]https://stackoverflow.com/questions/79776751/how-to-find-printed-document-in-image[/url]