1. 程式人生 > >使用OpenCV2.x計算影象的水平和垂直積分投影

使用OpenCV2.x計算影象的水平和垂直積分投影

          注:本文參考了wwl33695的一遍博文,地址如下:http://blog.csdn.net/wwl33695/article/details/8566742, 感謝你的支援!

         測試影象為lena.jpg,

        OK,下面開始積分投影的問題:  ( 執行環境:VS2012+opencv2.4.10

        1.重要的函式說明:

           這個函式初試化一個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完後垂直和水平積分投影的見解,由於剛入門不久,如果有錯誤或者待修正的地方,請各位可以指出。謝謝!