您的位置:首页 > 运维架构

使用OpenCV2.x计算图像的水平和垂直积分投影

2015-04-21 21:39 966 查看
注:本文参考了wwl33695的一遍博文,地址如下:http://blog.csdn.net/wwl33695/article/details/8566742,
感谢你的支持!

测试图像为lena.jpg,

OK,下面开始积分投影的问题: (
运行环境:VS2012+opencv2.4.10)

1.重要的函数说明:

[code=c++] 
	Mat paintX = Mat::ones( src.rows, src.cols, CV_8UC1 );    
        Mat paintY = Mat::ones( src.rows, src.cols, CV_8UC1 );


这个函数初试化一个Mat,所有元素的值均为1.高为src.rows,宽为src.cols ,只有一个通道。

2. adaptiveThreshold(src_gray, src_binary, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 25, 10);

阈值化函数,这个的各个参数的含义,就不再详细说明了。主要申明一点:

当第五个参数为:THRESH_BINARY_INV 时:输入的灰度图像就被二值化了,为0或者maxValue(在这里就是255);

3. Mat类中元素的遍历问题:在这里我提供两种基本的方法,网络上的博客关于这个问题有更加详细的办法。

方法一:利用opencv提供的Mat::at 方法解决

比如:

for( i=0; i<src_binary.cols; i++) //列
	{
	    for( j=0; j<src_binary.rows; j++)      //行
	    {
		if( src_binary.at<uchar>( j, i ) == 0)      
		    { /*your code*/}
	    }
	}

方法二:利用 opencv中的Mat::ptr 方法

比如:

for( x=0; x<src_binary.cols; x++)
	{		
		for(y=0; y<src_binary.rows; y++)
		{
			uchar* myptr_v = src_binary.ptr<uchar>(y);  //逐行扫描,返回每行的指针
			{/*your code */}
		}
	}


注:这里的代码的有些变量可能不明白,没关系的下面有完整的代码。


4.实现代码1

#include <iostream>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>

using namespace std;
using namespace cv;

char* wnd_binary = "二值图像";
char* wnd_X = "垂直积分投影";
char* wnd_Y = "水平积分投影";
String imgname = "../lena.jpg";

int main()
{
	Mat src = imread(imgname);
	Mat src_gray,src_binary,paintX,paintY;

	//创建两个图像框,用于绘制投影图  (黑底,0 黑,  1 白)
      paintX = Mat::zeros( src.rows, src.cols, CV_8UC1 );       
	paintY = Mat::zeros( src.rows, src.cols, CV_8UC1 );

	//Mat paintX( src.cols, src.rows, CV_8UC1, Scalar( 0, 0, 0));
	//Mat paintY( src.cols, src.rows, CV_8UC1, Scalar( 0, 0, 0));
	//转化为灰度图像
	cout<<"paintX.cols = "<<paintX.cols<<endl;
	cout<<"paintX.rows = "<<paintX.rows<<endl;

	cvtColor(src, src_gray, CV_RGB2GRAY);
	//二值化图像
	adaptiveThreshold(src_gray, src_binary, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 25, 10);
	int* v = new int[src.cols*2];
	int* h = new int[src.rows*2];
	cout<<"src.cols = "<<src.cols<<endl;
	cout<<"src.rows = "<<src.rows<<endl;
	memset(v, 0, src.cols*2);
	memset(h, 0, src.rows*2);
         //方法一的实现
	/*
	int i,j;
   //垂直方向进行累加(积分)
	for( i=0; i<src_binary.cols; i++) //列
	{
		for( j=0; j<src_binary.rows; j++)      //行
		{
			if( src_binary.at<uchar>( j, i ) == 0)      //统计的是黑色像素的数量
				v[i]++;
		}
	}
	//绘制垂直方向上的投影
	for( i=0; i<src_binary.cols; i++)
	{	
		for( j=0; j<v[i]; j++)
		{
			paintX.at<uchar>( j, i ) = 255;        //填充白色的像素
		}
	}
	//水平方向进行累加(积分)
	for( i=0; i<src_binary.rows; i++) //行
	{
		for( j=0; j<src_binary.cols; j++)      //列
		{
			if( src_binary.at<uchar>( i, j ) == 0)       //统计黑色像素的数量
				h[i]++;
		}
	}
	//绘制水平方向上的投影
	for( i=0; i<src_binary.rows; i++)
	{	
		for( j=0; j<h[i]; j++)
		{
			paintY.at<uchar>( i, j ) = 255;        //填充白色的像素
		}
	}
	*/
        //方法二的实现
	int x,y;
	for( x=0; x<src_binary.cols; x++)
	{		
		for(y=0; y<src_binary.rows; y++)
		{
			uchar* myptr_v = src_binary.ptr<uchar>(y);        //逐行扫描,返回每行的指针
			if( myptr_v[x] == 0 )
			  v[x]++;  
		}
	}
	for( x=0; x<src_binary.cols; x++)
	{
		for(y=0; y<v[x]; y++)
		{
			uchar* myptr_x = paintX.ptr<uchar>(y);
			myptr_x[x] = 255;
		}
	}
	for( x=0; x<src_binary.rows; x++)
	{
		uchar* myptr_h = src_binary.ptr<uchar>(x);
		for(y=0; y<src_binary.cols; y++)
		{
			if( myptr_h[y] == 0 )
				h[x]++;
		}
	}
	for( x=0; x<src_binary.rows; x++)
	{
		uchar* myptr_y = paintY.ptr<uchar>(x);
		for(y=0; y<h[x]; y++)
		{
			myptr_y[y] = 255;
		}
	}
	namedWindow(wnd_binary, CV_WINDOW_AUTOSIZE);
	namedWindow(wnd_X, CV_WINDOW_AUTOSIZE);
	namedWindow(wnd_Y, CV_WINDOW_AUTOSIZE);
	//显示图像
	imshow(wnd_binary, src_binary);
	imshow(wnd_X, paintX);
	imshow(wnd_Y, paintY);
	waitKey(0);
	return 0;
}
5.运行结果











6.实现代码二(一种相反投影方式)



#include <iostream>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

using namespace std;
using namespace cv;

char* wnd_binary = "二值图像";
char* wnd_X = "垂直积分投影";
char* wnd_Y = "水平积分投影";

int main()
{
	Mat src = imread("../lena.jpg");
	Mat src_gray,src_binary,paintX,paintY;
	//创建两个图像框,用于绘制投影图  (设置为白底,0 黑,  1 白)
	paintX = Mat::ones( src.rows, src.cols, CV_8UC1 );       
	paintY = Mat::ones( src.rows, src.cols, CV_8UC1 );

	cout<<"paintX.cols = "<<paintX.cols<<endl;
	cout<<"paintX.rows = "<<paintX.rows<<endl;
	//创建两张白底的图像
	for( int row=0; row<src.rows; row++)   //行
	{
		for( int col=0; col<src.cols; col++)      //列
		{
			paintX.at<uchar>(row, col) = 255;
			paintY.at<uchar>(row, col) = 255;			
     	}
	}	
	//转化为灰度图像
	cvtColor(src, src_gray, CV_RGB2GRAY);
	//二值化图像
	adaptiveThreshold(src_gray, src_binary, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 25, 10);
	int* v = new int[src.cols*4];
	int* h = new int[src.rows*4];
	cout<<"src.cols = "<<src.cols<<endl;
	cout<<"src.rows = "<<src.rows<<endl;
	memset(v, 0, src.cols*4);
	memset(h, 0, src.rows*4);	
	int i,j;
	//方法一遍历
	//垂直方向进行累加(积分)
	for( i=0; i<src_binary.cols; i++) //列
	{
		for( j=0; j<src_binary.rows; j++)      //行
		{
			if( src_binary.at<uchar>( j, i ) == 255)      //统计的是白色像素的数量
				v[i]++;
		}
	}
	//绘制垂直方向上的投影
	for( i=0; i<src_binary.cols; i++)
	{	
		for( j=0; j<v[i]; j++)
		{
			paintX.at<uchar>( j, i ) = 0;  //填充黑色的像素
		}
	}
	//水平方向进行累加(积分)
	for( i=0; i<src_binary.rows; i++) //行
	{
		for( j=0; j<src_binary.cols; j++)      //列
		{
			if( src_binary.at<uchar>( i, j ) == 255)   //统计白色像素的数量
				h[i]++;
		}
	}
	//绘制水平方向上的投影
	for( i=0; i<src_binary.rows; i++)
	{	
		for( j=0; j<h[i]; j++)
		{
			paintY.at<uchar>( i, j ) = 0;   //填充黑色的像素
		}
	}
	//方法二遍历
	/*
	int x,y;
	 //垂直积分投影
	for( x=0; x<src_binary.cols; x++)
	{		
		for(y=0; y<src_binary.rows; y++)
		{
			uchar* myptr_v = src_binary.ptr<uchar>(y);  //逐行扫描,返回每行的指针
			if( myptr_v[x] == 255 )
			  v[x]++;  
		}
	}
	for( x=0; x<src_binary.cols; x++)
	{
		for(y=0; y<v[x]; y++)
		{
			uchar* myptr_x = paintX.ptr<uchar>(y);
			myptr_x[x] = 0;
		}
	}
	//水平积分投影
	for( x=0; x<src_binary.rows; x++)
	{
		uchar* myptr_h = src_binary.ptr<uchar>(x);
		for(y=0; y<src_binary.cols; y++)
		{
			if( myptr_h[y] == 255 )
				h[x]++;
		}
	}

	for( x=0; x<src_binary.rows; x++)
	{
		uchar* myptr_y = paintY.ptr<uchar>(x);
		for(y=0; y<h[x]; y++)
		{
			myptr_y[y] = 0;
		}
	}
	*/
	namedWindow(wnd_binary, CV_WINDOW_AUTOSIZE);
	namedWindow(wnd_X, CV_WINDOW_AUTOSIZE);
	namedWindow(wnd_Y, CV_WINDOW_AUTOSIZE);
	//显示图像
	imshow(wnd_binary, src_binary);
	imshow(wnd_X, paintX);
	imshow(wnd_Y, paintY);
    waitKey(0);
	return 0;
}


7.运行结果










8.小结

上面就是我对利用OpenCV2.x完后垂直和水平积分投影的见解,由于刚入门不久,如果有错误或者待修正的地方,请各位可以指出。谢谢!


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐