opencv(一):图像规整

来源:互联网 发布:中国软件国际百度 编辑:程序博客网 时间:2024/05/29 16:47

前言

在使用caffe训练好的模型测试手写字符图片的时候,发现测试集图片和训练集图片在样式上不太一致,导致测试准确率很低。所以在测试之前需要对图片预处理使其规整。

基本思路

读入一幅图片-》将其转换为灰度图-》将其进行自适应二值化-》将图片进行黑白反转,以保持与训练集一致-》查找图片中的最大连通域-》在原图上框出最大连通域的外接矩形-》取出感兴趣的字符区域-》采用三种方式将取出的字符区域图片变换成原来的大小。

代码实现

运行环境:vs2010+opencv2.4.10
采用的主要函数汇总:
cvtColor();颜色空间转换;
adaptiveThreshold();自适应二值化
findContours();提取轮廓
contourArea();计算轮廓面积
boundingRect();计算轮廓的垂直边界最小矩形
rectangle();画矩形
resize();图像缩放
具体代码如下:

#include<iostream>#include<opencv2/opencv.hpp>#include<opencv2/core/core.hpp>#include<opencv2/highgui/highgui.hpp>using namespace cv;int main(){    Mat img=imread("1.png");    //判断图片是否正确读入    if(img.empty())    {        std::cout<<"read error!"<<std::endl;        return -1;    }    namedWindow("原图");    imshow("原图", img);    //将彩色图转换成灰度图    Mat sample;    cvtColor(img, sample, COLOR_BGR2GRAY);    //将图片进行自适应二值化    int threshold_type=CV_THRESH_BINARY;    int adaptive_method=CV_ADAPTIVE_THRESH_GAUSSIAN_C;    int blocksize=31;    double offset=15;    Mat sample_erzhi;    adaptiveThreshold(sample, sample_erzhi, 255, adaptive_method, threshold_type, blocksize, offset);    //将图片进行黑白反转    for(int i=0; i<100; i++)    {        for(int j=0; j<100; j++)        {            sample_erzhi.at<uchar>(i,j)=255-sample_erzhi.at<uchar)(i,j);        }    }    namedWindow("二值反转");    imshow("二值反转", sample_erzhi);    //查找连通域,计算面积,并保留最大面积    vector<vector<Point>> storage;    vector<Point> contmax;    vector<Vec4i> hierarchy;    Mat sample_tmp=sample_erzhi.clone();    Mat sample_rect;    sample_erzhi,copyTo(sample_rect);    findContours(sample_erzhi, storage, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);    double maxArea=0.0;    Rect rect(0,0,0,0);    for(int i=0; i<storage.size(); i++)    {        double area=fabs(contoursArea(storage[i]));        if(area>maxArea)        {            maxArea=area;            contmax=storage[i];            rect=boundingRect(contmax);        }    }    //在二值反转后的图上画出最大连通域的外接方框    cvtColor(sample_rect, sample_rect, CV_GRAY2BGR);    rectangle(sample_rect, Point(rect.x, rect.y), Point(rect.x+rect.width, rect.y+rect.height), Scalar(0,0,255), 1,8,0);    namedWindow("框图");    imshow("框图", sample_rect);    //取出感兴趣的字符区域    Mat sample_roi;    sample_roi=sample_tmp(Rect(rect.x, rect.y, rect.width, rect.height));    //方法一填充成原图大小    Mat roi1=sample_roi.clone();    int rewidth1=((float)60/rect.height)*rect.width;    resize(roi1, roi1, Size(rewidth1, 60));    Mat dst1=Mat::zeros(100,100, sample_roi.type());    for(int j=0; j<60; j++)    {        for(int i=0; i<rewidth1; i++)        {            dst1.at<uchar>((100-60)/2+j, (100-rewidth1)/2+i)=roi1.at<uchar>(j,i);        }    }    namedWindow("方法一");    imshow("方法一", dst1);    //方法二填充成原图大小    Mat roi2=sample_roi.clone();    int rewidth2=((float)100/rect.height)*rect.width;    resize(roi2, roi2, Size(rewidth2, 100));    Mat dst2=Mat::zeros(100,100, sample_roi.type());    if(rewidth2<=100)    {            for(int j=0; j<100; j++)            {                for(int i=0; i<rewidth2; i++)                {                    dst2.at<uchar>(j, (100-rewidth2)/2+i)=roi2.at<uchar>(j,i);                }            }    }    else    {        for(int j=0; j<100; j++)       {           for(int i=0; i<100; i++)           {               dst2.at<uchar>(j,i)=roi2.at<uchar>(j, (100-rewidth2)/2+i);           }       }      }      namedWindow("方法二");      imshow("方法二", dst2);      //方法三      Mat dst3=Mat::zeros(100,100, sample_roi.type());      for(int j=0; j<rect.height; j++)      {          for(int i=0; i<rect.widht; i++)          {              dst3.at<uchar>((100-rect.height)/2+j, (100-rect.width)/2+i)=roi.at<uchar>(j,i);             }        }        nameWindow("方法三");        imshow("方法三",dst3);        waitKey(50000);    }

运行结果:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

opencv使用过程中的一点注意事项:
1、Mat img1=imread(“1.png”);
Mat img2=img1;
这种情况下不会为img2单独分配空间,img2和img1共享内存空间,改变其中一个将间接改变另外一个。
2、img2.at(j,i);
j对应着图像的高,i对应着图像的宽。
resize(img2, img2, dx, dy);
dx对应着图像的宽, dy对应着图像的高。

原创粉丝点击