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;
}
分割原图
水平投影图
分割结果图
垂直切割
#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;
}
原图和垂直投影图
切割结果图
上一篇: 4种基本光照模型