使用轮廓模板匹配进行简单数字识别
大体思想就是准备好一个数字模板,查找到每个数字的轮廓后通过每个轮廓x坐标值来确保模板轮廓与数字相对应,测试图片同理,循环匹配来获得识别结果文章来源:https://www.toymoban.com/news/detail-813559.html
因为模板与测试图片都是白底黑字只包含数字,所以没有过多图像处理,如果测试图片较复杂,需考虑先将待识别区域分隔开,此处不做过多介绍文章来源地址https://www.toymoban.com/news/detail-813559.html
python代码
import cv2
import os
import numpy as np
from PIL import Image
def sort_contours(cnts): # 排序
boundingBoxes =[cv2.boundingRect(c) for c in cnts]
(cnts,boundingBoxes) = zip(*sorted(zip(cnts,boundingBoxes),key=lambda b: b[1][i],reverse=False))
return cnts
# 模板
tempimg = cv2.imread('./numbertemp.png')
refimg = cv2.cvtColor(tempimg, cv2.COLOR_BGR2GRAY)
refimg = cv2.threshold(refimg, 10, 255, cv2.THRESH_OTSU)[1]
refimg = cv2.bitwise_not(refimg)
contours, hierarchy = cv2.findContours(refimg.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# cv2.drawContours(tempimg, contours, -1, (0, 0, 255), 3)
# cv2.imshow('tempimg', tempimg)
# cv2.waitKey(0)
contours = sort_contours(contours)
digits = {} #模板
for (i, c) in enumerate(contours):
(x, y, w, h) = cv2.boundingRect(c)
roi = refimg[y:y + h, x:x + w]
roi = cv2.resize(roi,(57,88))
# cv2.imshow('temproi', roi)
# cv2.waitKey(0)
digits[i] = roi # 对应模板
# 测试
testimg = cv2.imread('./test2.jpg')
trefimg = cv2.cvtColor(testimg, cv2.COLOR_BGR2GRAY)
trefimg = cv2.threshold(trefimg, 10, 255, cv2.THRESH_OTSU)[1]
trefimg = cv2.bitwise_not(trefimg)
testcontours, testhierarchy = cv2.findContours(trefimg.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# cv2.drawContours(testimg, testcontours, -1, (0, 0, 255), 3)
# cv2.imshow('testimg', testimg)
# cv2.waitKey(0)
testcontours = sort_contours(testcontours)
groupOutput = []
for c in testcontours:
(x, y, w, h) = cv2.boundingRect(c)
roi = trefimg[y:y + h, x:x + w]
# 判断是否为‘-’或‘.’
# 统计白色像素点的个数
white_pixels = np.count_nonzero(roi == 255)
# 计算白色区域的占比
white_ratio = white_pixels / (roi.shape[0] * roi.shape[1])
if white_ratio > 0.8:
if roi.shape[1]/roi.shape[0] >= 2:
groupOutput.append('-')
else:
groupOutput.append('.')
continue
roi = cv2.resize(roi,(57,88))
scores = []
for (digit, digitROI) in digits.items():
result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)
(_, score, _, _) = cv2.minMaxLoc(result)
scores.append(score)
groupOutput.append(str(np.argmax(scores))) # 得到数字
# 输出结果
s = ''.join(groupOutput) # 将列表拼接为字符串
result = float(s)
formatted_result = format(result, '.3f') # 格式化结果,保留三位小数
print(formatted_result)
C++代码
///Test 轮廓排序
std::vector<std::vector<Point>> sortContours(std::vector<std::vector<Point>> cnts)
{
std::vector<cv::Rect> boundingBoxes;
for (const auto c : cnts)
{
boundingBoxes.push_back(cv::boundingRect(c));
}
std::sort(
std::begin(cnts),
std::end(cnts),
[boundingBoxes, cnts](const std::vector<cv::Point> a, const std::vector<cv::Point> b) {
return boundingBoxes[std::distance(std::begin(cnts), std::find(std::begin(cnts), std::end(cnts), a))].x <
boundingBoxes[std::distance(std::begin(cnts), std::find(std::begin(cnts), std::end(cnts), b))].x;
}
);
return cnts;
}
///Test 数字识别
float OpenCVDataUtils::digitalrecognition(cv::Mat imgIn)
{
// 模板
cv::Mat tempimg = cv::imread("/home/numbertemp.png");
cv::Mat refimg;
cv::cvtColor(tempimg, refimg, cv::COLOR_BGR2GRAY);
cv::threshold(refimg, refimg, 10, 255, cv::THRESH_OTSU);
bitwise_not(refimg, refimg);
std::vector<std::vector<Point>> tempcontours; //轮廓列表
cv::findContours(refimg, tempcontours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
std::vector<std::vector<Point>> sortedContours = sortContours(tempcontours);
std::map<int, cv::Mat> digits;
for (uint i = 0; i < sortedContours.size(); i++)
{
cv::Rect rect = cv::boundingRect(sortedContours[i]);
int x = rect.x;
int y = rect.y;
int w = rect.width;
int h = rect.height;
cv::Mat roi = refimg(cv::Rect(x, y, w, h));
cv::resize(roi, roi, cv::Size(57, 88)); // 调整大小
digits[i] = roi;
}
// 测试
cv::Mat trefimg;
cv::cvtColor(imgIn, trefimg, cv::COLOR_BGR2GRAY);
cv::threshold(trefimg, trefimg, 10, 255, cv::THRESH_OTSU);
bitwise_not(trefimg, trefimg);
std::vector<std::vector<Point>> tcontours; //轮廓列表
cv::findContours(trefimg, tcontours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
std::vector<std::vector<Point>> tsortedContours = sortContours(tcontours);
std::vector<std::string> groupOutput;
for (const auto c : tsortedContours) {
cv::Rect rect = cv::boundingRect(c);
int x = rect.x;
int y = rect.y;
int w = rect.width;
int h = rect.height;
cv::Mat roi = trefimg(cv::Rect(x, y, w, h));
int whitePixels = cv::countNonZero(roi == 255);
double whiteRatio = static_cast<double>(whitePixels) / (roi.rows * roi.cols);
if (whiteRatio > 0.8) {
if (static_cast<double>(roi.cols) / roi.rows >= 2) {
groupOutput.push_back("-");
} else {
groupOutput.push_back(".");
}
continue;
}
cv::resize(roi, roi, cv::Size(57, 88));
std::vector<double> scores;
for (const auto digit : digits) {
cv::Mat digitROI = digit.second;
cv::Mat result;
cv::matchTemplate(roi, digitROI, result, cv::TM_CCOEFF);
cv::Point minLoc, maxLoc;
double score;
cv::minMaxLoc(result, nullptr, &score, nullptr, &maxLoc);
scores.push_back(score);
}
int maxIndex = std::distance(scores.begin(), std::max_element(scores.begin(), scores.end()));
groupOutput.push_back(std::to_string(maxIndex));
}
// 将向量拼接为字符串
std::string s;
for (const auto str : groupOutput) {
s += str;
}
qDebug() << QString::fromStdString(s);
// 将字符串转换为浮点数
float result = std::stof(s);
return result;
}
到了这里,关于opencv数字识别(python/c++)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!