该程序实现打印体数字的图像识别
该程序是基于控制台的程序
其中Program文件为主程序,主要体现目的性的主流程;SimpleOCR文件为主要逻辑实现文件;ImageInfo文件定义了一个供查询的训练、测试图像数据结构。
程序流程如下:
1、调用了一个自定义类simpleOCR的构造函数,查询发现,程序并没有实现此构造函数,即啥也没做。
2、调用simpleOCR.ReadTrainingImages函数,读取Numbers目录下所有的png文件。
主要代码如下:
2.1 foreach (var dir in new DirectoryInfo(path).GetDirectories())遍历给定目录下的子目录
2.2 var groupId = int.Parse(dir.Name);得到目录名或该目录下文件的标签
2.3 foreach (var imageFile in dir.GetFiles(ext)) 得到该目录下的所有文件
2.4 var image = processTrainingImage(new Mat(imageFile.FullName, ImreadModes.GrayScale));
该代码将读取图片并将图片处理为同样大小和单通道。具体逻辑为
2.4.1 Cv2.Threshold(gray, threshImage, 80, 255, ThresholdTypes.BinaryInv); 对图片做二值化处理
2.4.2 查找图片的外轮廓
Point[][] contours;
HierarchyIndex[] hierarchyIndexes;
Cv2.FindContours(
threshImage,
out contours,
out hierarchyIndexes,
mode: RetrievalModes.CComp,
method: ContourApproximationModes.ApproxSimple);
2.4.3 根据轮廓得到图片的最小外接矩形,并复制图片
var boundingRect = Cv2.BoundingRect(contour);
var roi = new Mat(threshImage, boundingRect);
2.4.4将图片重置大小为10*10
var resizedImage = new Mat();
Cv2.Resize(roi, resizedImage, new Size(10, 10)); //resize to 10X10
2.4.5 将图片设置为单通道
resizedImage.ConvertTo(resizedImageFloat, MatType.CV_32FC1); //convert to float
result = resizedImageFloat.Reshape(1, 1);
2.5将该规范图片存入list的数据结构
var images = new List<ImageInfo>();
images.Add(new ImageInfo
{
Image = image,
ImageId = imageId++,
ImageGroupId = groupId
});
3、调用 var knn = simpleOCR.TrainData(trainingImages);开始训练
此函数和常见的cv knn训练相同,不再分析,代码如下:
public KNearest TrainData(IList<ImageInfo> trainingImages)
{
var samples = new Mat();
foreach (var trainingImage in trainingImages)
{
samples.PushBack(trainingImage.Image);
}
var labels = trainingImages.Select(x => x.ImageGroupId).ToArray();
var responses = new Mat(labels.Length, 1, MatType.CV_32SC1, labels);
var tmp = responses.Reshape(1, 1); //make continuous
var responseFloat = new Mat();
tmp.ConvertTo(responseFloat, MatType.CV_32FC1); // Convert to float
var kNearest = KNearest.Create();
kNearest.Train(samples, SampleTypes.RowSample, responseFloat); // Train with sample and responses
return kNearest;
}
4、调用simpleOCR.DoOCR(knn, @"..\..\Samples\sample1.png");进行测试。
这个函数也比较有研究价值
首先依然是灰度和二值化处理
v2.CvtColor(src, gray, ColorConversionCodes.BGRA2GRAY);
var threshImage = new Mat();
Cv2.Threshold(gray, threshImage, Thresh, ThresholdMaxVal, ThresholdTypes.BinaryInv);
接着用FindContours寻找要识别的图片的外轮廓
Point[][] contours;
HierarchyIndex[] hierarchyIndexes;
Cv2.FindContours(
threshImage,
out contours,
out hierarchyIndexes,
mode: RetrievalModes.CComp,
method: ContourApproximationModes.ApproxSimple);
然后对每一个封闭的外轮廓找到rect并完成框图绘制
var contour = contours[contourIndex];
var boundingRect = Cv2.BoundingRect(contour); //Find bounding rect for each contour
Cv2.Rectangle(src,
new Point(boundingRect.X, boundingRect.Y),
new Point(boundingRect.X + boundingRect.Width, boundingRect.Y + boundingRect.Height),
new Scalar(0, 0, 255),
2);
接着选择该区域,进行大小和通道转换
var roi = new Mat(threshImage, boundingRect); //Crop the image
var resizedImage = new Mat();
var resizedImageFloat = new Mat();
Cv2.Resize(roi, resizedImage, new Size(10, 10)); //resize to 10X10
resizedImage.ConvertTo(resizedImageFloat, MatType.CV_32FC1); //convert to float
var result = resizedImageFloat.Reshape(1, 1);
接着用knn的函数进行识别
var detectedClass = (int)kNearest.FindNearest(result, 1, results, neighborResponses, dists);
最后利用puttext函数将数字写在新的目标图片上面
Cv2.PutText(
dst,
detectedClass.ToString(CultureInfo.InvariantCulture),
new Point(boundingRect.X, boundingRect.Y + boundingRect.Height),
0,
1,
new Scalar(0, 255, 0),
2);
当然,待识别的可能有很多图片,即原先找到的外轮廓可能很多,下面继续识别就可以了。
contourIndex = hierarchyIndexes[contourIndex].Next;
完毕
该博客介绍了一个基于控制台的图像数字识别程序,主要流程包括读取Numbers目录下的png文件,对图像进行二值化、轮廓检测、最小外接矩形提取、重置大小及通道转换等预处理,然后使用KNN进行训练和识别。程序通过FindContours找到图像轮廓,裁剪并调整大小,最后用KNearest找到最近邻进行识别。
&spm=1001.2101.3001.5002&articleId=123248021&d=1&t=3&u=938e1eecf61b4982befcfb31733c23fc)
398

被折叠的 条评论
为什么被折叠?



