qq_32304207 2022-09-08 13:18 采纳率: 83.3%
浏览 105
已结题

使用open CV提取图像

img


此图为2值图,请教把液晶区域裁剪出来的代码,谢谢。 后续打算学习把符号小数点和数字裁剪出来,谢谢。

  • 写回答

4条回答 默认 最新

  • 万里鹏程转瞬至 人工智能领域优质创作者 2022-09-08 17:06
    关注
    获得2.30元问题酬金

    颜色翻转以下,然后进行中值滤波,最后求连通域,得到最大的连通域(现有图片中的最大黑色区域)。
    对最大连通域进行闭运算,将连通域中的数字变成白色。
    用连通域做mask,得到目标图。

    #include <iostream>
    #include <opencv2/opencv.hpp>
    #include <opencv2/highgui.hpp>
    #include <opencv2/imgproc.hpp>
    
    using namespace std;
    using namespace cv;
    
    //修改自以下链接,博主添加了pad,使两列图像边多了空格
    //https ://blog.csdn.net/Beking17113/article/details/122304671
    void multipleImage(vector<Mat> imgVector, Mat& dst, int imgCols, int MAX_PIXEL = 600)
    {
        //两列图像间的空白区域
        int pad = 10;
        int imgNum = imgVector.size();
        //选择图片最大的一边 将最大的边按比例变为300像素
        Size imgOriSize = imgVector[0].size();
        int imgMaxPixel = max(imgOriSize.height, imgOriSize.width);
        //获取最大像素变为MAX_PIXEL的比例因子
        double prop = imgMaxPixel < MAX_PIXEL ? (double)imgMaxPixel / MAX_PIXEL : MAX_PIXEL / (double)imgMaxPixel;
        Size imgStdSize(imgOriSize.width * prop, imgOriSize.height * prop); //窗口显示的标准图像的Size
    
        Mat imgStd; //标准图片
        Point2i location(0, 0); //坐标点(从0,0开始)
        //Mat imgWindow(imgStdSize.height * ((imgNum - 1) / imgCols + 1), imgStdSize.width * imgCols+ pad * imgCols-pad, imgVector[0].type());
        int imgRows = (imgNum - 1) / imgCols + 1;
        Mat imgWindow = Mat::zeros(imgStdSize.height * imgRows + pad * imgRows - pad, imgStdSize.width * imgCols + pad * imgCols - pad, imgVector[0].type());
        for (int i = 0; i < imgNum; i++)
        {
            location.x = (i % imgCols) * (imgStdSize.width + pad);
            location.y = (i / imgCols) * imgStdSize.height;
            resize(imgVector[i], imgStd, imgStdSize, prop, prop, INTER_LINEAR); //设置为标准大小
    
            //将imgStd复制到imgWindow的指定区域中
            imgStd.copyTo(imgWindow(Rect(location, imgStdSize)));
        }
        dst = imgWindow;
    }
    
    void imshows( string title, vector<Mat> imgVector, int imgCols = -1) {
        Mat dst;
    
        if (imgCols == -1) {
            imgCols = imgVector.size();
        }
        multipleImage(imgVector, dst, imgCols);
        namedWindow(title);
        imshow(title, dst);
        imwrite(title + ".png", dst);
    }
    Mat readImg(string path) {
        Mat img = imread(path, 0);//左侧:图片路径
        resize(img, img, { 512,512 });
        int thres_ = 128;
        cv::threshold(img, img, thres_, 255, THRESH_BINARY);//大于阈值返回 最大值 255 小于返回0
        cv::medianBlur(img, img, 3);
        return img;
    }
    Mat findLargesrArea(Mat srcImage)
    {
        Mat temp;
        Mat labels;
        srcImage.copyTo(temp);
    
        //1. 标记连通域
        int n_comps = connectedComponents(temp, labels, 4, CV_16U);
        vector<int> histogram_of_labels;
        for (int i = 0; i < n_comps; i++)//初始化labels的个数为0
        {
            histogram_of_labels.push_back(0);
        }
    
        int rows = labels.rows;
        int cols = labels.cols;
        for (int row = 0; row < rows; row++) //计算每个labels的个数
        {
            for (int col = 0; col < cols; col++)
            {
                histogram_of_labels.at(labels.at<unsigned short>(row, col)) += 1;
            }
        }
        histogram_of_labels.at(0) = 0; //将背景的labels个数设置为0
    
        //2. 计算最大的连通域labels索引
        int maximum = 0;
        int max_idx = 0;
        for (int i = 0; i < n_comps; i++)
        {
            if (histogram_of_labels.at(i) > maximum)
            {
                maximum = histogram_of_labels.at(i);
                max_idx = i;
            }
        }
    
        //3. 将最大连通域标记为1
        for (int row = 0; row < rows; row++)
        {
            for (int col = 0; col < cols; col++)
            {
                if (labels.at<unsigned short>(row, col) == max_idx)
                {
                    labels.at<unsigned short>(row, col) = 255;
                }
                else
                {
                    labels.at<unsigned short>(row, col) = 0;
                }
            }
        }
    
        //4. 将图像更改为CV_8U格式
        labels.convertTo(labels, CV_8U);
        return labels;
    }
    int main(int argc, char* argv[])
    {
        string p1 = "D:\\test.png";
        Mat im1 = readImg(p1);
        Mat inv = 255 - im1;
        Mat element = getStructuringElement(MORPH_RECT, Size(9, 9));
        morphologyEx(inv, inv, MORPH_OPEN, element);//消除毛刺,删除部分连通域
    
        //获取最大的连通域
        Mat maxareo = findLargesrArea(inv);
    
        //闭合连通域中的数字
        Mat element2 = getStructuringElement(MORPH_RECT, Size(71, 71));
        Mat maxareo_close, maxareo_close_erode,result;
        morphologyEx(maxareo, maxareo_close, MORPH_CLOSE, element2);//消除毛刺,删除部分连通域
    
        Mat element3 = getStructuringElement(MORPH_RECT, Size(31, 31));
        morphologyEx(maxareo_close, maxareo_close_erode, MORPH_ERODE, element3);//因为图像边缘也被连接了,这里做删除
    
        result = maxareo_close_erode.mul(im1);
        imshows("二值图", {im1,inv ,maxareo_close_erode,result },2);
        //imshow( inv);
        waitKey();
    }
    
    
    

    img

    按照前面的代码,再优化以下流程,得到以下结果

    int main(int argc, char* argv[])
    {
        string p1 = "D:\\test.png";
        Mat im1 = readImg(p1);
        Mat inv = 255 - im1;
        Mat element = getStructuringElement(MORPH_RECT, Size(9, 9));
        morphologyEx(inv, inv, MORPH_OPEN, element);//消除毛刺,删除部分连通域
    
        //获取最大的连通域
        Mat maxareo = findLargesrArea(inv);
    
        //闭合连通域中的数字
        Mat element2 = getStructuringElement(MORPH_RECT, Size(71, 71));
        Mat maxareo_close, maxareo_close_big_erode,result;
        morphologyEx(maxareo, maxareo_close, MORPH_CLOSE, element2);//消除毛刺,删除部分连通域
        Mat maxareo_close_big = Mat::zeros({ im1.rows+40,im1.cols+40}, im1.type());
        maxareo_close.copyTo(maxareo_close_big(Rect({20,20}, im1.size())));
    
        Mat element3 = getStructuringElement(MORPH_RECT, Size(39, 39));
        morphologyEx(maxareo_close_big, maxareo_close_big_erode, MORPH_ERODE, element3);//因为图像边缘也被连接了,这里做删除
        Mat maxareo_close_erode = maxareo_close_big_erode(Rect({ 20,20 }, im1.size()));
    
        result = maxareo_close_erode.mul(im1);
        imshows("二值图", {im1,inv ,maxareo_close_erode,result },2);
        //imshow( inv);
        waitKey();
    }
    
    

    img

    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 9月16日
  • 修改了问题 9月8日
  • 创建了问题 9月8日

悬赏问题

  • ¥100 求汇川机器人IRCB300控制器和示教器同版本升级固件
  • ¥15 用visualstudio2022创建vue项目后无法启动
  • ¥15 x趋于0时tanx-sinx极限可以拆开算吗
  • ¥500 把面具戴到人脸上,请大家贡献智慧
  • ¥15 任意一个散点图自己下载其js脚本文件并做成独立的案例页面,不要作在线的,要离线状态。
  • ¥15 各位 帮我看看如何写代码,打出来的图形要和如下图呈现的一样,急
  • ¥30 c#打开word开启修订并实时显示批注
  • ¥15 如何解决ldsc的这条报错/index error
  • ¥15 VS2022+WDK驱动开发环境
  • ¥30 关于#java#的问题,请各位专家解答!