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