opencv数字识别(python/c++)

使用轮廓模板匹配进行简单数字识别

大体思想就是准备好一个数字模板,查找到每个数字的轮廓后通过每个轮廓x坐标值来确保模板轮廓与数字相对应,测试图片同理,循环匹配来获得识别结果

因为模板与测试图片都是白底黑字只包含数字,所以没有过多图像处理,如果测试图片较复杂,需考虑先将待识别区域分隔开,此处不做过多介绍

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;
}

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
PyCharm是一款常用的Python集成开发环境(IDE),它提供了丰富的功能和工具来帮助开发者编写、调试和运行Python代码。关于数字识别,PyCharm本身并没有直接提供数字识别的功能,但你可以使用PyCharm来开发和运行数字识别相关的Python程序。 数字识别是指通过计算机程序将手写或打印的数字图像转化为对应的数字。在Python中,有很多库可以用来实现数字识别,其中最常用的是OpenCV和TensorFlow。你可以使用PyCharm来创建一个Python项目,并导入这些库来进行数字识别的开发。 以下是一个简单的示例代码,使用OpenCV和KNN算法进行手写数字识别: ```python import cv2 import numpy as np # 加载训练数据 digits = cv2.imread('digits.png', 0) digits = np.array(digits, dtype=np.float32) labels = np.arange(10) # 创建KNN分类器 knn = cv2.ml.KNearest_create() knn.train(digits, cv2.ml.ROW_SAMPLE, labels) # 加载测试图像 test_image = cv2.imread('test_image.png', 0) # 预处理测试图像 test_image = cv2.resize(test_image, (20, 20)) test_image = np.array(test_image, dtype=np.float32) test_image = test_image.reshape((1, 400)) # 进行数字识别 ret, result, neighbors, dist = knn.findNearest(test_image, k=5) # 输出识别结果 print(int(result[0][0])) ``` 这段代码首先加载训练数据,然后创建一个KNN分类器并进行训练。接下来,加载测试图像并进行预处理,最后使用KNN分类器进行数字识别,并输出识别结果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值