由于对基本的Opencv的矩阵的数据类型不太熟悉,以及它们之间的转换,数据的存取都比较陌生,虽然在写这个程序的时候思路很清楚,却总是出错,找到的并不是想要的边缘位置。今天终于搞好啦,关于OpenCV的矩阵类型及操作还要多加熟悉和使用啊!!下面是实现程序及效果图:
#include "stdafx.h"
#include "highgui.h"
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void GetLevelGrad();
int main()
{
IplImage* GrayImage;
const char *pstrImageName = "D:\\picture\\New\\1 (2).bmp";
GrayImage = cvLoadImage(pstrImageName, CV_LOAD_IMAGE_GRAYSCALE);
cvShowImage("灰度图像",GrayImage);
Mat SmothImage ;
//Mat AverageVal = cvCreateMat(1, GrayImage->width, CV_32FC1);
Mat Gray_Image(GrayImage);
GaussianBlur( Gray_Image, SmothImage, Size( 3, 3 ), 0, 0 );
//imshow("高斯滤波处理",SmothImage);
int iWidth = SmothImage.cols;
int iHeight = SmothImage.rows;
int i,j;
CvMat* averageValue_level = cvCreateMat( 1, iWidth, CV_32FC1 );
CvMat* averageValue_vertical = cvCreateMat( iHeight,1, CV_32FC1 );
for (i=0;i<iWidth;i++)
{
float value = 0;
for (j=0;j<iHeight;j++)
{
value = value + (float)SmothImage.at<uchar>(j,i);
}
value = value/(float)iHeight;
CV_MAT_ELEM( *averageValue_level, float,0, i ) = value;
//AverageValue.at<uchar>(0,i) = value;
//printf("%f\n",CV_MAT_ELEM( *averageValue, float,0, i ) );
}
cv::Mat AverageValue_level = cv::Mat(averageValue_level,true);
//cvShowImage("所有列灰度均值",averageValue);
cv::Mat GradValue_level(1,iWidth, CV_32FC1);
for (i=0;i<iWidth-1;i++)
{
GradValue_level.at<float>(0,i) = (float)CV_MAT_ELEM( *averageValue_level, float,0, i+1 ) -(float)CV_MAT_ELEM( *averageValue_level, float,0, i );
printf("%f\n",GradValue_level.at<float>(0,i));
}
///////////////////////////////垂直方向/////////////////////
for (j=0;j<iHeight;j++)
{
float value = 0;
for (i=0;i<iWidth;i++)
{
value = value + (float)SmothImage.at<uchar>(j,i);
}
value = value/(float)iWidth;
CV_MAT_ELEM( *averageValue_vertical, float,j, 0 ) = value;
//AverageValue.at<uchar>(0,i) = value;
//printf("%f\n",CV_MAT_ELEM( *averageValue, float,0, i ) );
}
cv::Mat AverageValue_vertical = cv::Mat(averageValue_vertical,true);
//cvShowImage("所有列灰度均值",averageValue_vertical);
cv::Mat GradValue_vertical(iHeight,1, CV_32FC1);
for (j=0;j<iHeight-1;j++)
{
GradValue_vertical.at<float>(j,0) = (float)CV_MAT_ELEM( *averageValue_vertical, float,j+1,0 ) -(float)CV_MAT_ELEM( *averageValue_vertical, float,j,0);
printf("%f\n",GradValue_vertical.at<float>(j,0));
}
GradValue_vertical.at<uchar>(iHeight-1,0) =0;
double minVal, maxVal,minVal_Vertical,maxVal_Vertical;
Point minLoc_level, maxLoc_level, matchLoc_level,minLoc_vertical,maxLoc_vertical;
minMaxLoc(GradValue_level, &minVal, &maxVal, &minLoc_level, &maxLoc_level, Mat() );
//////////////////////////////垂直方向////////////////////////////////////////
minMaxLoc(GradValue_vertical, &minVal_Vertical, &maxVal_Vertical, &minLoc_vertical, &maxLoc_vertical, Mat() );
circle( SmothImage, maxLoc_level, 3, Scalar(255,0,255), -1, 8, 0 );
circle( SmothImage, maxLoc_vertical, 3, Scalar(255,0,255), -1, 8, 0 );
//circle( SmothImage, minLoc_vertical, 3, Scalar(255,0,255), -1, 8, 0 );
printf("x坐标:%f",(float)maxLoc_level.x);
printf("y坐标: %f",(float)maxLoc_vertical.y);
Point matchPoint;
matchPoint.x = maxLoc_level.x-1;
matchPoint.y = maxLoc_vertical.y-1;
Point center;
center.x = maxLoc_level.x+(minLoc_level.x-maxLoc_level.x+4)/2;
center.y = maxLoc_vertical.y+ (minLoc_vertical.y-maxLoc_vertical.y+4)/2;
rectangle( SmothImage, Rect(matchPoint, Size(minLoc_level.x-maxLoc_level.x+4, minLoc_vertical.y-maxLoc_vertical.y+4 ) ), Scalar(0), 1, 8, 0 );
//circle(SmothImage,center,(minLoc_level.x-maxLoc_level.x+4)/2,Scalar(0,0,0),2,8,0);
imshow("边界点所在位置",SmothImage);
cvWaitKey();
}
因为本程序的主要思想是基于一阶导数求梯度的,所以找到的边缘位置会有1~2个像素点的偏离。后面的代码段对位置有一点小的调整。