Я разрабатываю функцию в приложении .NET 8 для автоматического обнаружения, точки зрения и обрезки визитной карточки с карты, загруженной пользователем, с использованием библиотеки OpenCVSharp4. Тем не менее, он постоянно терпит неудачу в более реалистичных, сложных ситуациях.
Проблема:
Алгоритм не может найти правильный контур визитной карточки в двух основных случаях:
Недовопроводный фон: например, белая визитная карта на светоцветной стойке. Например, визитная карточка в узорной таблице PlaceMat или деревянной зернистости. (План А и план б) найти карту. Код структурирован для сохранения исходного изображения, так и (попыток) обрезанного изображения. < /P>
Вот полный метод C#: < /p>
// using OpenCvSharp;
// using SixLabors.ImageSharp;
// ...and other necessary using statements at the top of the file.
public static async Task SaveBusinessCardAsync(IFormFile businessCardFile)
{
if (businessCardFile == null || !businessCardFile.ContentType.StartsWith("image"))
{
return (null, null);
}
try
{
// Prep paths and save the original file (unchanged)
string fileStorageRoot = AppSettingsHelper.GetSystemConfigValue("strFileServer");
string folderFullPath = Path.Combine(fileStorageRoot, "Upload_Address", "BusinessCards");
if (!Directory.Exists(folderFullPath)) Directory.CreateDirectory(folderFullPath);
string originalFileName = businessCardFile.FileName;
string guid = Guid.NewGuid().ToString();
string originalSavePath = Path.Combine(folderFullPath, $"{{{guid}}}_orig.jpg");
string croppedSavePath = Path.Combine(folderFullPath, $"{{{guid}}}_crop.jpg");
using (var image = await SixLabors.ImageSharp.Image.LoadAsync(businessCardFile.OpenReadStream()))
{
await image.SaveAsJpegAsync(originalSavePath, new JpegEncoder { Quality = 90 });
}
using (var stream = businessCardFile.OpenReadStream())
using (Mat originalImage = Mat.FromStream(stream, ImreadModes.Color))
{
if (originalImage.Empty()) throw new Exception("OpenCV could not read the image file.");
// Pre-resize the image for faster and more stable processing
double scale = 1000.0 / originalImage.Width;
var newSize = new OpenCvSharp.Size(1000, (int)(originalImage.Height * scale));
using Mat resizedImage = new Mat();
Cv2.Resize(originalImage, resizedImage, newSize);
OpenCvSharp.Point[] largestContour = null;
// --- Plan A: Canny Edge Detection Based Approach ---
using (Mat grayImage = new Mat())
using (Mat blurredImage = new Mat())
using (Mat edges = new Mat())
using (Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(7, 7)))
using (Mat closedEdges = new Mat())
{
Cv2.CvtColor(resizedImage, grayImage, ColorConversionCodes.BGR2GRAY);
Cv2.GaussianBlur(grayImage, blurredImage, new OpenCvSharp.Size(5, 5), 0);
double median = Cv2.Mean(blurredImage).Val0;
double lowerThreshold = Math.Max(0, 0.7 * median);
double upperThreshold = Math.Min(255, 1.3 * median);
Cv2.Canny(blurredImage, edges, lowerThreshold, upperThreshold);
Cv2.MorphologyEx(edges, closedEdges, MorphTypes.Close, kernel, iterations: 3);
OpenCvSharp.Point[][] contours;
HierarchyIndex[] hierarchy;
Cv2.FindContours(closedEdges, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
double imageArea = resizedImage.Width * resizedImage.Height;
var sortedCandidates = contours
.Select(c => Cv2.ApproxPolyDP(c, Cv2.ArcLength(c, true) * 0.02, true))
.Where(poly =>
{
if (poly.Length != 4) return false;
double area = Cv2.ContourArea(poly);
if (area < imageArea * 0.10) return false;
var rect = Cv2.BoundingRect(poly);
double aspectRatio = (double)rect.Width / rect.Height;
return aspectRatio > 1.2 && aspectRatio < 2.2;
})
.OrderByDescending(c => Cv2.ContourArea(c))
.ToList();
if (sortedCandidates.Any())
{
var firstCandidate = sortedCandidates[0];
if (Cv2.ContourArea(firstCandidate) < imageArea * 0.95)
{
largestContour = firstCandidate;
}
else if (sortedCandidates.Count > 1)
{
largestContour = sortedCandidates[1];
}
}
}
// --- Plan B: Text/Content Block Based Approach (if Plan A fails) ---
if (largestContour == null)
{
using Mat grayForText = new Mat();
Cv2.CvtColor(resizedImage, grayForText, ColorConversionCodes.BGR2GRAY);
using Mat thresh = new Mat();
Cv2.AdaptiveThreshold(grayForText, thresh, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.BinaryInv, 11, 2);
using Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(15, 3));
using Mat morph = new Mat();
Cv2.MorphologyEx(thresh, morph, MorphTypes.Close, kernel, iterations: 2);
OpenCvSharp.Point[][] textContours;
HierarchyIndex[] hierarchy;
Cv2.FindContours(morph, out textContours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
if (textContours.Length > 0)
{
var allPoints = textContours.SelectMany(c => c);
Rect boundingRect = Cv2.BoundingRect(allPoints);
largestContour = new OpenCvSharp.Point[] {
new OpenCvSharp.Point(boundingRect.X, boundingRect.Y),
new OpenCvSharp.Point(boundingRect.X + boundingRect.Width, boundingRect.Y),
new OpenCvSharp.Point(boundingRect.X + boundingRect.Width, boundingRect.Y + boundingRect.Height),
new OpenCvSharp.Point(boundingRect.X, boundingRect.Y + boundingRect.Height)
};
}
}
Mat croppedImage = null;
if (largestContour != null)
{
// Rescale points back to the original image for high-quality crop
Point2f[] sourcePoints = largestContour.Select(p => new Point2f((float)(p.X / scale), (float)(p.Y / scale))).ToArray();
// ... (Perspective transform logic is here) ...
}
Mat imageToSave = croppedImage ?? originalImage;
// ... (Saving logic is here) ...
croppedImage?.Dispose();
return (FilePath: croppedSavePath, FileName: originalFileName);
}
}
catch (Exception ex)
{
// ... logging and error handling
return (null, null);
}
}
< /code>
Мой вопрос: < /p>
Даже с этим двухплановым подходом я все еще не могу получить надежный культ на примере изображений. Кажется, что мой алгоритм недостаточно надежна. Например: < /p>
Существуют ли лучшие методы предварительной обработки для улучшения слабых ребра на изображениях с низким содержанием контрасти? Алгоритмические подходы были бы очень оценены.
Спасибо!
Подробнее здесь: https://stackoverflow.com/questions/797 ... rp-failing
Устойчивое обнаружение и обрезка визитных карточек с OpenCVSharp в C# (сбое на низкоконтрастных и текстурированных фонах ⇐ C#
Место общения программистов C#
1754465004
Anonymous
Я разрабатываю функцию в приложении .NET 8 для автоматического обнаружения, точки зрения и обрезки визитной карточки с карты, загруженной пользователем, с использованием библиотеки OpenCVSharp4. Тем не менее, он постоянно терпит неудачу в более реалистичных, сложных ситуациях.
Проблема:
Алгоритм не может найти правильный контур визитной карточки в двух основных случаях:
Недовопроводный фон: например, белая визитная карта на светоцветной стойке. Например, визитная карточка в узорной таблице PlaceMat или деревянной зернистости. (План А и план б) найти карту. Код структурирован для сохранения исходного изображения, так и (попыток) обрезанного изображения. < /P>
Вот полный метод C#: < /p>
// using OpenCvSharp;
// using SixLabors.ImageSharp;
// ...and other necessary using statements at the top of the file.
public static async Task SaveBusinessCardAsync(IFormFile businessCardFile)
{
if (businessCardFile == null || !businessCardFile.ContentType.StartsWith("image"))
{
return (null, null);
}
try
{
// Prep paths and save the original file (unchanged)
string fileStorageRoot = AppSettingsHelper.GetSystemConfigValue("strFileServer");
string folderFullPath = Path.Combine(fileStorageRoot, "Upload_Address", "BusinessCards");
if (!Directory.Exists(folderFullPath)) Directory.CreateDirectory(folderFullPath);
string originalFileName = businessCardFile.FileName;
string guid = Guid.NewGuid().ToString();
string originalSavePath = Path.Combine(folderFullPath, $"{{{guid}}}_orig.jpg");
string croppedSavePath = Path.Combine(folderFullPath, $"{{{guid}}}_crop.jpg");
using (var image = await SixLabors.ImageSharp.Image.LoadAsync(businessCardFile.OpenReadStream()))
{
await image.SaveAsJpegAsync(originalSavePath, new JpegEncoder { Quality = 90 });
}
using (var stream = businessCardFile.OpenReadStream())
using (Mat originalImage = Mat.FromStream(stream, ImreadModes.Color))
{
if (originalImage.Empty()) throw new Exception("OpenCV could not read the image file.");
// Pre-resize the image for faster and more stable processing
double scale = 1000.0 / originalImage.Width;
var newSize = new OpenCvSharp.Size(1000, (int)(originalImage.Height * scale));
using Mat resizedImage = new Mat();
Cv2.Resize(originalImage, resizedImage, newSize);
OpenCvSharp.Point[] largestContour = null;
// --- Plan A: Canny Edge Detection Based Approach ---
using (Mat grayImage = new Mat())
using (Mat blurredImage = new Mat())
using (Mat edges = new Mat())
using (Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(7, 7)))
using (Mat closedEdges = new Mat())
{
Cv2.CvtColor(resizedImage, grayImage, ColorConversionCodes.BGR2GRAY);
Cv2.GaussianBlur(grayImage, blurredImage, new OpenCvSharp.Size(5, 5), 0);
double median = Cv2.Mean(blurredImage).Val0;
double lowerThreshold = Math.Max(0, 0.7 * median);
double upperThreshold = Math.Min(255, 1.3 * median);
Cv2.Canny(blurredImage, edges, lowerThreshold, upperThreshold);
Cv2.MorphologyEx(edges, closedEdges, MorphTypes.Close, kernel, iterations: 3);
OpenCvSharp.Point[][] contours;
HierarchyIndex[] hierarchy;
Cv2.FindContours(closedEdges, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
double imageArea = resizedImage.Width * resizedImage.Height;
var sortedCandidates = contours
.Select(c => Cv2.ApproxPolyDP(c, Cv2.ArcLength(c, true) * 0.02, true))
.Where(poly =>
{
if (poly.Length != 4) return false;
double area = Cv2.ContourArea(poly);
if (area < imageArea * 0.10) return false;
var rect = Cv2.BoundingRect(poly);
double aspectRatio = (double)rect.Width / rect.Height;
return aspectRatio > 1.2 && aspectRatio < 2.2;
})
.OrderByDescending(c => Cv2.ContourArea(c))
.ToList();
if (sortedCandidates.Any())
{
var firstCandidate = sortedCandidates[0];
if (Cv2.ContourArea(firstCandidate) < imageArea * 0.95)
{
largestContour = firstCandidate;
}
else if (sortedCandidates.Count > 1)
{
largestContour = sortedCandidates[1];
}
}
}
// --- Plan B: Text/Content Block Based Approach (if Plan A fails) ---
if (largestContour == null)
{
using Mat grayForText = new Mat();
Cv2.CvtColor(resizedImage, grayForText, ColorConversionCodes.BGR2GRAY);
using Mat thresh = new Mat();
Cv2.AdaptiveThreshold(grayForText, thresh, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.BinaryInv, 11, 2);
using Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(15, 3));
using Mat morph = new Mat();
Cv2.MorphologyEx(thresh, morph, MorphTypes.Close, kernel, iterations: 2);
OpenCvSharp.Point[][] textContours;
HierarchyIndex[] hierarchy;
Cv2.FindContours(morph, out textContours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
if (textContours.Length > 0)
{
var allPoints = textContours.SelectMany(c => c);
Rect boundingRect = Cv2.BoundingRect(allPoints);
largestContour = new OpenCvSharp.Point[] {
new OpenCvSharp.Point(boundingRect.X, boundingRect.Y),
new OpenCvSharp.Point(boundingRect.X + boundingRect.Width, boundingRect.Y),
new OpenCvSharp.Point(boundingRect.X + boundingRect.Width, boundingRect.Y + boundingRect.Height),
new OpenCvSharp.Point(boundingRect.X, boundingRect.Y + boundingRect.Height)
};
}
}
Mat croppedImage = null;
if (largestContour != null)
{
// Rescale points back to the original image for high-quality crop
Point2f[] sourcePoints = largestContour.Select(p => new Point2f((float)(p.X / scale), (float)(p.Y / scale))).ToArray();
// ... (Perspective transform logic is here) ...
}
Mat imageToSave = croppedImage ?? originalImage;
// ... (Saving logic is here) ...
croppedImage?.Dispose();
return (FilePath: croppedSavePath, FileName: originalFileName);
}
}
catch (Exception ex)
{
// ... logging and error handling
return (null, null);
}
}
< /code>
Мой вопрос: < /p>
Даже с этим двухплановым подходом я все еще не могу получить надежный культ на примере изображений. Кажется, что мой алгоритм недостаточно надежна. Например: < /p>
Существуют ли лучшие методы предварительной обработки для улучшения слабых ребра на изображениях с низким содержанием контрасти? Алгоритмические подходы были бы очень оценены.
Спасибо!
Подробнее здесь: [url]https://stackoverflow.com/questions/79726952/robust-business-card-detection-and-cropping-with-opencvsharp-in-c-sharp-failing[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия