欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

opencv利用投影法进行水平切割和垂直切割

程序员文章站 2024-03-15 08:52:05
...

水平投影切割

#include<iostream>
#include <opencv2/opencv.hpp>  
using namespace std;
using namespace cv;
int main()
{
    IplImage * src = cvLoadImage("img1.jpg");
    IplImage *dst = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
    IplImage *img = cvCreateImage(cvGetSize(src), src->depth, src->nChannels);
    cvThreshold(src, dst, 100, 255, CV_THRESH_BINARY);
    IplImage* painty = cvCreateImage(cvGetSize(dst), IPL_DEPTH_8U, 1);
    cvZero(painty);
    int* h = new int[dst->height];
    memset(h, 0, dst->height * 4);
    int x, y;
    CvScalar s, t;//可以用来存放4个double数值的数组,一般用来存放像素值(不一定是灰度值哦)的,最多可以存放4个通道的 

    for (y = 0; y<dst->height; y++)
    {
        for (x = 0; x<dst->width; x++)
        {
            s = cvGet2D(dst, y, x);

            if (s.val[0] == 0)
                h[y]++;
        }
    }
    for (y = 0; y<dst->height; y++)
    {
        for (x = 0; x<h[y]; x++)
        {
            t.val[0] = 255;
            cvSet2D(painty, y, x, t);

        }
    }

    vector<Mat> roiList;//用于储存分割出来的每个字符
    int startIndex = 0;//记录进入字符区的索引
    int endIndex = 0;//记录进入空白区域的索引
    bool inBlock = false;//是否遍历到了字符区内
    char szName[30] = { 0 };
    for (int i = 0; i < dst->height; ++i)
    {
        if (!inBlock && h[i] !=0)//进入字符区了
        {
            inBlock = true;
            startIndex = i;
            cout << "startIndex is " << startIndex << endl;
        }
        else if (h[i] ==0 && inBlock)//进入空白区了
        {
            endIndex = i;
            inBlock = false;
            Mat dst1(src, 0);
            Mat roiImg;
            if (endIndex - startIndex>3)
            {
                roiImg = dst1(Range(startIndex, endIndex + 1), Range(0, dst1.cols));
                roiList.push_back(roiImg);
                sprintf(szName, "aa%d.jpg", i);
                imshow(szName, roiImg);
                imwrite(szName, roiImg);
            }           
        }
    }   

    cvNamedWindow("二值图像", 1);
    cvNamedWindow("水平投影", 1);
    cvShowImage("二值图像", dst);
    cvShowImage("水平投影", painty);
    cvWaitKey(0);
    cvDestroyAllWindows();
    cvReleaseImage(&dst);
    cvReleaseImage(&painty);
    return 0;
}

分割原图
opencv利用投影法进行水平切割和垂直切割
水平投影图
opencv利用投影法进行水平切割和垂直切割
分割结果图
opencv利用投影法进行水平切割和垂直切割

垂直切割

#include<iostream>
#include <opencv2/opencv.hpp>  
using namespace std;
using namespace cv;
int main()
{
    IplImage * src = cvLoadImage("aa146.jpg");
    IplImage *dst = cvCreateImage(cvGetSize(src), 8, 1);
    IplImage *img = cvCreateImage(cvGetSize(src), 8, 1);
    //cvSmooth(src, src, CV_BLUR, 3, 3, 0, 0);
    cvCvtColor(src, img, CV_BGR2GRAY);
    cvThreshold(img, dst, 135, 255, CV_THRESH_BINARY);
    IplImage* paintx = cvCreateImage(cvGetSize(dst), IPL_DEPTH_8U, 1);
    cvZero(paintx);
    int* v = new int[dst->width];   
    memset(v, 0, dst->width * 4);
    int x, y;
    CvScalar s, t;//可以用来存放4个double数值的数组,一般用来存放像素值(不一定是灰度值哦)的,最多可以存放4个通道的  
    //垂直投影  
    for (x = 0; x<dst->width; x++)
    {
        for (y = 0; y<dst->height; y++)
        {
            s = cvGet2D(dst, y, x); //cvGet2D() 的函数原型是 : CvScalar cvGet2D (const CvArr * arr, int idx0, int idx1);   
            //函数返回的是一个CvScalar 容器,其参数中也有两个方向的坐标,  
            //但跟我们平常习惯的坐标不一样的是,idx0代表是的行,即高度,对应于我们平常坐标系的y,  
            //idx1代表的是列,即宽度,对应于我们平常坐标系的x,cvSet2D() 也类似。          
            //printf("area == %lf\n",s);  
            if (s.val[0] == 0)
                v[x]++;
        }
    }

    for (x = 0; x<dst->width; x++)
    {
        for (y = 0; y<v[x]; y++)
        {
            t.val[0] = 255;
            cvSet2D(paintx, y, x, t);
        }
    }
    cvShowImage("原图", src);
    cvShowImage("垂直投影", paintx);
    //分割

    vector<Mat> roiList;//用于储存分割出来的每个字符
    int startIndex = 0;//记录进入字符区的索引
    int endIndex = 0;//记录进入空白区域的索引
    bool inBlock = false;//是否遍历到了字符区内
    char szName[30] = { 0 };
    for (int i = 0; i < dst->width; ++i)
    {
        if (!inBlock && v[i] != 0)//进入字符区了
        {
            inBlock = true;
            startIndex = i;
            cout << "startIndex is " << startIndex << endl;
        }
        else if (v[i] == 0 && inBlock)//进入空白区了
        {
            endIndex = i;
            inBlock = false;
            Mat dst1(src, 0);
            Mat roiImg;
            if (endIndex - startIndex>3)
            {
                roiImg = dst1(Range(0, dst1.rows), Range(startIndex, endIndex + 1));
                roiList.push_back(roiImg);
                sprintf(szName, "aaa%d.jpg", i);
                imshow(szName, roiImg);
                imwrite(szName, roiImg);
            }
        }
    }
    cvWaitKey(0);
    cvDestroyAllWindows();
    cvReleaseImage(&dst);
    cvReleaseImage(&paintx);
    return 0;
}

原图和垂直投影图
opencv利用投影法进行水平切割和垂直切割
切割结果图
opencv利用投影法进行水平切割和垂直切割