OPENCV图像变换-2
一.经典霍夫变换
霍夫变换是图像处理中的一种特征提取技术,该方法通过在一个参数空间中通过计算累计结果的局部最大值来得到一个符合该特定形状的集合,作为结果.
运用两个坐标空间之间的变换,将一个空间中具有相同形状的曲线或者是直线映射到另一个坐标空间中的一个点形成峰值,从而将统计任意性状化为统计峰值问题.
opencv中,霍夫线变换市一中寻找直线的方法,在使用霍夫线变换之前,要先对图像进行边缘检测的处理,霍夫变换的直接输入为阈值化之后的二值图像
opencv至此三种不同的霍夫线变换,标准霍夫变换(SHT),多尺度霍夫变换(MSHT),累计概率霍夫变换(PPHT).
PPHT是标准霍夫变换的一种改进方式,并不像标准霍夫变换一样将累加平面的所有的点累加,而只是累加其中的一小部分,该想法是如果峰值能够足够高,那么只需要一小部分时间来寻找它就够了.
霍夫变化的基本原理是:任意一条笛卡尔坐标下的直线,都可以化为极坐标形式,直线上的某一点其经过的所有直线的参数构成一条曲线,如果图片中有足够多的点,这些点的曲线会有一个共同的焦点,那么这个交点处的值就是这一条直线,只要设置足够多的阈值,就可以找出这一条直线.
API:void houghLins(源图像,输出寻找到的直线,double 像素为单位的距离精度,double 弧度为单位的角度精度,int 累加平面的阈值,double 多尺度变换的除数距离,double 多尺度时的单位角度的除数距离);
注:源为单通道,二值化图像,目标为输出矢量,并非mat,而是以极坐标参数对定义,一个vector里面包含若干参数对,距离精度为直线搜索时,距离尺寸的增长单位,角度精度为直线搜索时,每次增长的角度精度,阈值参数是当某一条直线被查找出来的时候,他在累加器中必须达到的累加器阈值,多尺度的角度精度和距离精度除数如果都为0,那么这是经典的霍夫变换.
经典霍夫变换的使用代码
Mat srcImage,srcImageGray,cannyImage;
vector<Vec2f>lines; //三个变量,距离精度rho 角度精度 theta 阈值参数 threshold
const int g_rhoMax = ;
int g_rhoValue; const int g_thetaMax = ;
int g_thetaValue; const int g_thresholdMax = ;
int g_thresholdValue; void onTrackBarrho(int pos,void* userData);
void onTrackBartheta(int pos,void* userData);
void onTrackBarThreshold(int pos,void* userData); int main(int argc,char* argv[])
{
srcImage = imread("F:\\opencv\\OpenCVImage\\HoughLine.jpg");
if(srcImage.channels() == )
{
srcImageGray = srcImage.clone();
}
else
{
cvtColor(srcImage, srcImageGray, CV_RGB2GRAY);
} namedWindow("src image");
namedWindow("line image"); g_rhoValue = ;
g_thetaValue = ;
g_thresholdValue = ;
createTrackbar("rho value", "line image", &g_rhoValue, g_rhoMax,onTrackBarrho,);
createTrackbar("theta value", "line image", &g_thetaValue, g_thetaMax,onTrackBartheta ,);
createTrackbar("threshold value", "line image", &g_thresholdValue, g_thresholdMax,onTrackBarThreshold,);
onTrackBarThreshold(g_thresholdValue,); imshow("src image", srcImageGray); moveWindow("src image", , );
moveWindow("line image", srcImageGray.cols*, ); waitKey();
return ;
} void onTrackBarrho(int pos,void* userData)
{
int rhoValue = g_rhoValue+;
int thetaValue = g_thetaValue+;
int threshold = g_thresholdValue+;
double theta = CV_PI/(double)thetaValue;
Canny(srcImageGray, cannyImage, , ,);
HoughLines(cannyImage, lines, rhoValue, theta, threshold,,);
imshow("canny image", cannyImage);
moveWindow("canny image", srcImageGray.cols, );
Mat tempImage(srcImageGray.rows,srcImageGray.cols,CV_8UC3,Scalar(,,));
for(size_t i = ; i < lines.size(); i++)
{
float rhoResult = lines[i][];
float thetaResult = lines[i][];
Point pt1,pt2;
double a = cos(thetaResult);
double b = sin(thetaResult);
double x0 = a*rhoResult;
double y0 = b*rhoResult;
pt1.x = cvRound(x0 + *(-b));
pt1.y = cvRound(y0 + *(a));
pt2.x = cvRound(x0 - *(-b));
pt2.y = cvRound(y0 - *(a));
line(tempImage, pt1, pt2, Scalar(,,),);
}
imshow("line image", tempImage);
}
void onTrackBartheta(int pos,void* userData)
{
int rhoValue = g_rhoValue+;
int thetaValue = g_thetaValue+;
int threshold = g_thresholdValue+;
double theta = CV_PI/(double)thetaValue;
Canny(srcImageGray, cannyImage, , ,);
HoughLines(cannyImage, lines, rhoValue, theta, threshold,,);
imshow("canny image", cannyImage);
moveWindow("canny image", srcImageGray.cols, );
Mat tempImage(srcImageGray.rows,srcImageGray.cols,CV_8UC3,Scalar(,,));
for(size_t i = ; i < lines.size(); i++)
{
float rhoResult = lines[i][];
float thetaResult = lines[i][];
Point pt1,pt2;
double a = cos(thetaResult);
double b = sin(thetaResult);
double x0 = a*rhoResult;
double y0 = b*rhoResult;
pt1.x = cvRound(x0 + *(-b));
pt1.y = cvRound(y0 + *(a));
pt2.x = cvRound(x0 - *(-b));
pt2.y = cvRound(y0 - *(a));
line(tempImage, pt1, pt2, Scalar(,,),);
}
imshow("line image", tempImage);
}
void onTrackBarThreshold(int pos,void* userData)
{
int rhoValue = g_rhoValue+;
int thetaValue = g_thetaValue+;
int threshold = g_thresholdValue+;
double theta = CV_PI/(double)thetaValue;
Canny(srcImageGray, cannyImage, , ,);
HoughLines(cannyImage, lines, rhoValue, theta, threshold,,);
imshow("canny image", cannyImage);
moveWindow("canny image", srcImageGray.cols, );
Mat tempImage(srcImageGray.rows,srcImageGray.cols,CV_8UC3,Scalar(,,));
for(size_t i = ; i < lines.size(); i++)
{
float rhoResult = lines[i][];
float thetaResult = lines[i][];
Point pt1,pt2;
double a = cos(thetaResult);
double b = sin(thetaResult);
double x0 = a*rhoResult;
double y0 = b*rhoResult;
pt1.x = cvRound(x0 + *(-b));
pt1.y = cvRound(y0 + *(a));
pt2.x = cvRound(x0 - *(-b));
pt2.y = cvRound(y0 - *(a));
line(tempImage, pt1, pt2, Scalar(,,),);
}
imshow("line image", tempImage);
}
二.累计概率霍夫变换
累计概率霍夫变换是使用的比较多的霍夫变换,因为和标准霍夫变换比起来,累计概率霍夫变换计算快一些,并且结果也足够精确.
API:void houghLineP(源图像,结果向量,double 进步距离,double 进角弧度,int 累计阈值,int 最小线段长度,int 同一行点与点之间的最小连接距离);
注:最小线段长度,默认为0,比这个参数短的线将不输出在结果中,连接最大距离,默认值为0,低于这个距离的将不构成同一根线,输出的点为四个元素的矢量,分别是(x1,y1,x2,y2);用vetc(vec4i)lines来表示,起点和终点坐标.
使用代码
Mat srcImage,srcGrayImage,cannyImage;
vector<Vec4i>lines; //lowThreshold 默?认¨?upThreshold为alowthtreshold的Ì?三¨y倍À?
const int g_lowThresholdMax = ;
int g_lowThresholdValue;
void onTrackBarCannyLowThreshold(int pos,void* userData);
#define CALC_UPTHRESHOLD_VALUE(value) value*3; //canny sobel 孔¡Á径?
const int g_cannySobelSizeMax = ;
int g_cannySobelSizeValue;
void onTrackBarCannySobelSize(int pos,void* userData); //hough 步?进?精?度¨¨
const int g_houghlineRhoMax = ;
int g_houghlineRhoValue;
void onTrackBarHoughlineRhoValue(int pos,void* userData); //houghlinep 角?度¨¨精?度¨¨
const int g_houghlineThetaMax = ;
int g_houghlineThetaValue;
void onTrackBarHoughlineThetaValue(int pos,void* userData); //累¤?计?阈D值¦Ì
const int g_houghlineThresholdMax = ;
int g_houghlineThresholdValue;
void onTrackBarHoughlineThresholdValue(int pos,void* userData); //最Á?小?线?段?长¡è度¨¨
const int g_houghlineMindistMax = ;
int g_houghlineMindistValue;
void onTrackBarHoughlineMindistValue(int pos,void* userData); int main(int argc,char* argv[])
{
srcImage = imread("F:\\opencv\\OpenCVImage\\HoughLineP.jpg");
if(srcImage.channels() == )
{
srcGrayImage = srcImage.clone();
}
else
{
cvtColor(srcImage, srcGrayImage, CV_RGB2GRAY);
} namedWindow("src image");
namedWindow("canny image");
namedWindow("dst image"); g_lowThresholdValue = ;
g_cannySobelSizeValue = ;
createTrackbar("low threshold", "canny image", &g_lowThresholdValue, g_lowThresholdMax,onTrackBarCannyLowThreshold,);
createTrackbar("sobel size", "canny image", &g_cannySobelSizeValue, g_cannySobelSizeMax,onTrackBarCannySobelSize,);
onTrackBarCannySobelSize(g_cannySobelSizeValue, ); g_houghlineRhoValue = ;
g_houghlineThetaValue = ;
g_houghlineMindistValue = ;
g_houghlineThresholdValue = ;
createTrackbar("rho value", "dst image", &g_houghlineRhoValue, g_houghlineRhoMax,onTrackBarHoughlineRhoValue,);
createTrackbar("theta value", "dst image", &g_houghlineThetaValue,g_houghlineThetaMax,onTrackBarHoughlineThetaValue,);
createTrackbar("threshold value", "dst image", &g_houghlineThresholdValue, g_houghlineThresholdMax,onTrackBarHoughlineThresholdValue,);
createTrackbar("min dist", "dst image", &g_houghlineMindistValue, g_houghlineMindistMax,onTrackBarHoughlineMindistValue,);
onTrackBarHoughlineRhoValue(g_houghlineRhoValue, ); imshow("src image", srcImage); moveWindow("src image", , );
moveWindow("canny image", srcGrayImage.cols, );
moveWindow("dst image", srcImage.cols*, ); waitKey();
return ;
} void onTrackBarCannyLowThreshold(int pos,void* userData)
{
int sobelSize = g_cannySobelSizeValue*+;
int lowThreshold = g_lowThresholdValue+;
int upThreshold = CALC_UPTHRESHOLD_VALUE(lowThreshold);
Canny(srcGrayImage, cannyImage, lowThreshold, upThreshold,sobelSize);
imshow("canny image", cannyImage);
} void onTrackBarCannySobelSize(int pos,void* userData)
{
int sobelSize = g_cannySobelSizeValue*+;
int lowThreshold = g_lowThresholdValue+;
int upThreshold = CALC_UPTHRESHOLD_VALUE(lowThreshold);
Canny(srcGrayImage, cannyImage, lowThreshold, upThreshold,sobelSize);
imshow("canny image", cannyImage);
} void onTrackBarHoughlineRhoValue(int pos,void* userData)
{
double rhoValue = g_houghlineRhoValue+;
double thetaValue = g_houghlineThetaValue+;
int thresholdValue = g_houghlineThresholdValue+;
int minDist = g_houghlineMindistValue+;
HoughLinesP(cannyImage, lines, rhoValue, CV_PI/thetaValue, thresholdValue,minDist);
Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(,,));
for (size_t i = ; i < lines.size(); i++) {
line(dstImage, Point(lines[i][],lines[i][]), Point(lines[i][],lines[i][]),Scalar(,,),LINE_4);
}
imshow("dst image", dstImage);
} void onTrackBarHoughlineThetaValue(int pos,void* userData)
{
double rhoValue = g_houghlineRhoValue+;
double thetaValue = g_houghlineThetaValue+;
int thresholdValue = g_houghlineThresholdValue+;
int minDist = g_houghlineMindistValue+;
HoughLinesP(cannyImage, lines, rhoValue, CV_PI/thetaValue, thresholdValue,minDist);
Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(,,));
for (size_t i = ; i < lines.size(); i++) {
line(dstImage, Point(lines[i][],lines[i][]), Point(lines[i][],lines[i][]),Scalar(,,),LINE_4);
}
imshow("dst image", dstImage);
} void onTrackBarHoughlineThresholdValue(int pos,void* userData)
{
double rhoValue = g_houghlineRhoValue+;
double thetaValue = g_houghlineThetaValue+;
int thresholdValue = g_houghlineThresholdValue+;
int minDist = g_houghlineMindistValue+;
HoughLinesP(cannyImage, lines, rhoValue, CV_PI/thetaValue, thresholdValue,minDist);
Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(,,));
for (size_t i = ; i < lines.size(); i++) {
line(dstImage, Point(lines[i][],lines[i][]), Point(lines[i][],lines[i][]),Scalar(,,),LINE_4);
}
imshow("dst image", dstImage);
} void onTrackBarHoughlineMindistValue(int pos,void* userData)
{
double rhoValue = g_houghlineRhoValue+;
double thetaValue = g_houghlineThetaValue+;
int thresholdValue = g_houghlineThresholdValue+;
int minDist = g_houghlineMindistValue+;
HoughLinesP(cannyImage, lines, rhoValue, CV_PI/thetaValue, thresholdValue,minDist);
Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(,,));
for (size_t i = ; i < lines.size(); i++) {
line(dstImage, Point(lines[i][],lines[i][]), Point(lines[i][],lines[i][]),Scalar(,,),LINE_4);
}
imshow("dst image", dstImage);
}
三.霍夫圆变换
霍夫圆变换与霍夫线变换的原理基本一致,任意一个圆上任意一个点也可以表示为以圆心,半径为代表的一个三维空间中的曲线,多个曲线的交点,代表一个确定的圆.
在OPENCV中,使用霍夫梯度法解决圆变换问题,具体过程是,首先对图像进行边缘检测,然后计算结果中不为0的值的XY方向的梯度,利用梯度累加斜率指定直线上的没一个点(斜率为指定最大值和最小值之间的距离),最后标记边缘图像中每一个非零像素的位置.,从二维累加器中选择候选中心.
霍夫圆变换的缺陷在于阈值设置如果比较低,那么算法消耗时间长,同心圆的间隔比较近的时候,倾向于保存半径最大的圆,并且霍夫梯度法在某些时候也会产生噪声.
API:void houghCircles(源图,结果向量,int 检测方法,int 输入图像和累加器的分辨率之比,int 圆心之间最小距离,double 算法高阈值,低阈值默认为高阈值1/2,double 圆心累累加器阈值,int 半径最小值,int 半径最大值);
注:源图像为八位单通道灰度图,目标向量为vecter<vec3f>,向量中存储的依次是圆心x,圆心y,半径r,检测方法目前只有霍夫梯度法HOUGH_GRENIENT ,霍夫梯度法默认高阈值100.低阈值为其1/2,圆心间距太小,多个相邻的圆会重合,太大,某些圆不能被检测出,累加器阈值太小,会检测出很多不存在的圆,阈值越大,越容易检测出完美的圆
另外,函数可能找不到合适的半径供用户使用,可以忽略半径,用额外的步骤确定.
使用例程
Mat srcImage,srcGrayImage;
vector<Vec3f>circles; //圆2形?最Á?小?距¨¤离¤?
const int g_houghcircleMinDistMax = ;
int g_houghcircleMinDistValue;
void onTrackBarMinDist(int pos,void* userData); //canny算?子Á¨®高?阈D值¦Ì
const int g_houghcircleThresholdUpMax = ;
int g_houghcircleThresholdUpValue;
void onTrackBarThresholdUp(int pos,void* userData); //圆2心?累¤?加¨®器¡Â阈D值¦Ì
const int g_houghcircleCenterThresholdMax = ;
int g_houghcircleCenterThresholdValue;
void onTrackBarCenterThreshold(int pos,void* userData); //最Á?小?半ã?径?
const int g_houghcircleMinRadiusMax = ;
int g_houghcircleMinRadiusValue;
void onTrackBarRadiusMin(int pos,void* userData); //最Á?大䨮半ã?径?
const int g_houghcircleMaxRadiusMax = ;
int g_houghcircleMaxRadiusValue;
void onTrackBarRadiusMax(int pos,void* userData); int main(int argc,char* argv[])
{
srcImage = imread("F:\\opencv\\OpenCVImage\\HoughCircle.jpg");
if(srcImage.channels() == )
{
cvtColor(srcImage, srcGrayImage, CV_RGB2GRAY);
}
else
{
srcGrayImage = srcImage.clone();
} namedWindow("src gray image");
namedWindow("dst image"); g_houghcircleMinDistValue = ;
g_houghcircleThresholdUpValue = ;
g_houghcircleCenterThresholdValue = ;
g_houghcircleMinRadiusValue = ;
g_houghcircleMaxRadiusValue = ;
createTrackbar("center min dist", "dst image", &g_houghcircleMinDistValue, g_houghcircleMinDistMax,onTrackBarMinDist,);
createTrackbar("canny threshold", "dst image", &g_houghcircleThresholdUpValue, g_houghcircleThresholdUpMax,onTrackBarThresholdUp,);
createTrackbar("center threshold", "dst image", &g_houghcircleCenterThresholdValue, g_houghcircleCenterThresholdMax,onTrackBarCenterThreshold,);
createTrackbar("min radius", "dst image", &g_houghcircleMinRadiusValue, g_houghcircleMinRadiusMax,onTrackBarRadiusMin,);
createTrackbar("max radius", "dst image", &g_houghcircleMaxRadiusValue, g_houghcircleMaxRadiusMax,onTrackBarRadiusMax,);
onTrackBarRadiusMin(g_houghcircleMinDistValue,); imshow("src gray image", srcGrayImage); moveWindow("src gray image", , );
moveWindow("dst image", srcGrayImage.cols, ); waitKey();
return ;
} void onTrackBarMinDist(int pos,void* userData)
{
int minDist = g_houghcircleMinDistValue+;
double cannyThreshold = (double)g_houghcircleThresholdUpValue+;
double centerThreshold = (double)g_houghcircleCenterThresholdValue+;
int minRadius = g_houghcircleMinRadiusValue+;
int maxRadius = g_houghcircleMaxRadiusValue+;
if(minRadius >= maxRadius)
{
imshow("dst image", srcGrayImage);
}
else
{
Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(,,));
HoughCircles(srcGrayImage, circles, HOUGH_GRADIENT, , minDist,cannyThreshold,centerThreshold,minRadius,maxRadius);
for (size_t i = ; i < circles.size(); i++) {
circle(dstImage, Point(circles[i][],circles[i][]), circles[i][], Scalar(,,));
}
imshow("dst image", dstImage);
}
}
void onTrackBarThresholdUp(int pos,void* userData)
{
int minDist = g_houghcircleMinDistValue+;
double cannyThreshold = (double)g_houghcircleThresholdUpValue+;
double centerThreshold = (double)g_houghcircleCenterThresholdValue+;
int minRadius = g_houghcircleMinRadiusValue+;
int maxRadius = g_houghcircleMaxRadiusValue+;
if(minRadius >= maxRadius)
{
imshow("dst image", srcGrayImage);
}
else
{
Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(,,));
HoughCircles(srcGrayImage, circles, HOUGH_GRADIENT, , minDist,cannyThreshold,centerThreshold,minRadius,maxRadius);
for (size_t i = ; i < circles.size(); i++) {
circle(dstImage, Point(circles[i][],circles[i][]), circles[i][], Scalar(,,),LINE_AA);
}
imshow("dst image", dstImage);
}
}
void onTrackBarCenterThreshold(int pos,void* userData)
{
int minDist = g_houghcircleMinDistValue+;
double cannyThreshold = (double)g_houghcircleThresholdUpValue+;
double centerThreshold = (double)g_houghcircleCenterThresholdValue+;
int minRadius = g_houghcircleMinRadiusValue+;
int maxRadius = g_houghcircleMaxRadiusValue+;
if(minRadius >= maxRadius)
{
imshow("dst image", srcGrayImage);
}
else
{
Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(,,));
HoughCircles(srcGrayImage, circles, HOUGH_GRADIENT, , minDist,cannyThreshold,centerThreshold,minRadius,maxRadius);
for (size_t i = ; i < circles.size(); i++) {
circle(dstImage, Point(circles[i][],circles[i][]), circles[i][], Scalar(,,));
}
imshow("dst image", dstImage);
}
}
void onTrackBarRadiusMax(int pos,void* userData)
{
int minDist = g_houghcircleMinDistValue+;
double cannyThreshold = (double)g_houghcircleThresholdUpValue+;
double centerThreshold = (double)g_houghcircleCenterThresholdValue+;
int minRadius = g_houghcircleMinRadiusValue+;
int maxRadius = g_houghcircleMaxRadiusValue+;
if(minRadius >= maxRadius)
{
imshow("dst image", srcGrayImage);
}
else
{
Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(,,));
HoughCircles(srcGrayImage, circles, HOUGH_GRADIENT, , minDist,cannyThreshold,centerThreshold,minRadius,maxRadius);
for (size_t i = ; i < circles.size(); i++) {
circle(dstImage, Point(circles[i][],circles[i][]), circles[i][], Scalar(,,));
}
imshow("dst image", dstImage);
}
}
void onTrackBarRadiusMin(int pos,void* userData)
{
int minDist = g_houghcircleMinDistValue+;
double cannyThreshold = (double)g_houghcircleThresholdUpValue+;
double centerThreshold = (double)g_houghcircleCenterThresholdValue+;
int minRadius = g_houghcircleMinRadiusValue+;
int maxRadius = g_houghcircleMaxRadiusValue+;
if(minRadius >= maxRadius)
{
imshow("dst image", srcGrayImage);
}
else
{
Mat dstImage(srcGrayImage.rows,srcGrayImage.cols,CV_8UC3,Scalar(,,));
HoughCircles(srcGrayImage, circles, HOUGH_GRADIENT, , minDist,cannyThreshold,centerThreshold,minRadius,maxRadius);
for (size_t i = ; i < circles.size(); i++) {
circle(dstImage, Point(circles[i][],circles[i][]), circles[i][], Scalar(,,));
}
imshow("dst image", dstImage);
}
}
四.重映射
重映射是指将一张图片上的某个指定位置的像素拷贝到目标图像的某一个位置上
API:void remap(源图,目的图,映射数组1,映射数组2,int 插值方式,int 边界模式,int 边界值)
注:源和目标都必须为八位单通道图像或者浮点单通道图像
使用例程
int main(int argc,char* argv[])
{
Mat srcImage,mapx,mapy,dstImage;
srcImage = imread("F:\\opencv\\OpenCVImage\\remap.jpg");
mapx.create(srcImage.size(), CV_32FC1);
mapy.create(srcImage.size(), CV_32FC1);
dstImage.create(srcImage.rows, srcImage.cols, srcImage.type()); //核?心?就¨ª是º?这a个?mapx 和¨ªmapy
for(int j = ; j < srcImage.rows;j++)
{
for (int i = ; i < srcImage.cols; i++)
{
mapx.at<float>(j,i) = static_cast<float>(i);
mapy.at<float>(j,i) = static_cast<float>(srcImage.rows-j);
}
}
remap(srcImage, dstImage, mapx, mapy, INTER_LINEAR,BORDER_CONSTANT,Scalar(,,));
imshow("src image", srcImage);
imshow("dst image", dstImage); moveWindow("src image", , );
moveWindow("dst image", srcImage.cols, ); waitKey();
return ;
}
五.仿射变换
集合中,一个向量空间进行一次线性变换并加上那个一次平移,变成另一个向量空间,叫做仿射变换,一个任意的仿射变换都可以表示成乘以一个矩阵,再加上一个向量的形式,
仿射变换可以实现图片的缩放,旋转,平移,其代表的是两张图片之间的映射关系.
API:void warpAffine(源图像,目标图像,变换矩阵,Size 输出图像尺寸,int 插值方式,int 边界模式,int 恒定边界取值)
注:源可以使多通道或者单通道,目标和源的类型一致,变换矩阵一般来说可以通过getRotationMatrix2D来获得,而不需要自己去实现.获得的是一个2*3的变换矩阵,插值方式默认为INTER_LINEAR,和RESIZE插值方式相似,但是又添加了两种新的插值方式,CV_WARP_FILL_OUTLIERS填充所有输出图像的像素,CV_WARP_INVERSE_MAP表明该变换试一次输出图像到输入图像的逆变换.
API Mat getRotationMatrix2D(Point源图的旋转中心,double 旋转角度,double 缩放系数)
注:该API反悔的矩阵可以作为仿射变换的变换矩阵使用
使用代码实际例程如下
Mat srcImage,dstImage,rotationImage;
const int g_angelMax = ;
int g_angelValue;
void onTrackBarRotationAngel(int pos,void* userData); const int g_scaleMax = ;//最Á?大䨮10倍À?缩?放¤?系¦Ì数ºy
int g_scaleValue;
void onTrackBarScale(int pos,void* userData); int main(int argc,char* argv[])
{
srcImage = imread("F:\\opencv\\OpenCVImage\\warpAffine.jpg");
namedWindow("src image");
namedWindow("dst image"); g_angelValue = ;
g_scaleValue = ;
createTrackbar("angel value", "dst image", &g_angelValue, g_angelMax,onTrackBarRotationAngel,);
createTrackbar("scale value", "dst image", &g_scaleValue, g_scaleMax,onTrackBarScale,);
onTrackBarRotationAngel(g_angelValue,); imshow("src image", srcImage); moveWindow("src image", , );
moveWindow("dst image", srcImage.cols, ); waitKey();
return ;
} void onTrackBarRotationAngel(int pos,void* userData)
{
if(g_scaleValue == )g_scaleValue = ;
double scale = 1.0/g_scaleValue;
rotationImage = getRotationMatrix2D(Point(srcImage.cols/,srcImage.rows/), g_angelValue, scale);
warpAffine(srcImage, dstImage, rotationImage, srcImage.size(),INTER_LINEAR);
imshow("dst image", dstImage);
} void onTrackBarScale(int pos,void* userData)
{
if(g_scaleValue == )g_scaleValue = ;
double scale = 1.0/g_scaleValue;
rotationImage = getRotationMatrix2D(Point(srcImage.cols/,srcImage.rows/), g_angelValue, scale);
warpAffine(srcImage, dstImage, rotationImage, srcImage.size(),INTER_LINEAR);
imshow("dst image", dstImage);
}
六.直方图均衡化
如果需要扩大图像的动态范围,最常使用的技术就是直方图均衡化,属于弧度变幻的一个重要应用,用一定的算法,使直方图大致平和的过程.拉伸像素强度的分布范围来增强图像的对比度,例如原先图像的像素灰度集中的100-200区域,那么将100-200区域的数据扩展到0-255,就属于直方图均衡化.
均衡化以后的图像只能近似的均匀分布,动态范围扩大,本质是扩大了量化间距,而量化级别反而减少了.这是一个缺点,均衡化以后可能会出现伪轮廓,或者消除原来图像的有效轮廓.
在泛白缓和的图像中,均衡化会合并一些像素灰度,从而增大对比度
原始图像对比度本省就比较高的,在均衡化会造成灰度调和,从而降低对比度
从色彩上说,均衡化会是图像的表现力更出色.
API:void equalizeHist(源图像,目标图像)
源和目标,都必须为八位单通道图像
使用实例
int main(int argc,char* argv[])
{
Mat srcImage,dstImage;
srcImage = imread("F:\\opencv\\OpenCVImage\\equalizeHist.jpg");
if(srcImage.channels() != )
{
cvtColor(srcImage, srcImage, CV_RGB2GRAY);
} equalizeHist(srcImage, dstImage); //Mat dstRgbImage(srcImage.rows,srcImage.cols,CV_8UC3);
//cvtColor(dstImage, dstRgbImage, CV_GRAY2BGR); imshow("src image", srcImage);
imshow("dst image", dstImage);
moveWindow("src image", , );
moveWindow("dst image", srcImage.cols, );
waitKey();
return ;
}
OPENCV图像变换-2的更多相关文章
- OPENCV图像变换-1
图像变换是指将一幅图像变换为图像数据的另一种表现形式,例如将图像进行傅立叶变换,或者对图像进行X,Y方向的求导等,经过这些变换,可以将图像数据处理中的某些问题换一个别的角度想办法,所以图像变换是图像处 ...
- OpenCV图像变换(仿射变换与透视变换)
仿射变换(affine transform)与透视变换(perspective transform)在图像还原.图像局部变化处理方面有重要意义.通常,在2D平面中,仿射变换的应用较多,而在3D平面中, ...
- OpenCV —— 图像变换
将一副图像转变成另一种表现形式 ,比如,傅里叶变换将图像转换成频谱分量 卷积 —— 变换的基础 cvFilter2D 源图像 src 和目标图像 dst 大小应该相同 注意:卷积核的系数应该是浮点类 ...
- python+opencv图像变换的两种方法cv2.warpAffine和cv2.warpPerspective
本文链接:https://blog.csdn.net/qq_27261889/article/details/80720359 # usr/bin/env python # coding: utf- ...
- OpenCV图像变换二 投影变换与极坐标变换实现圆形图像修正
投影变换 在放射变换中,物体是在二维空间中变换的.如果物体在三维空间中发生了旋转,那么这种变换就成为投影变换,在投影变换中就会出现阴影或者遮挡,我们可以运用二维投影对三维投影变换进行模块化,来处理阴影 ...
- <学习opencv>图像变换
拉伸.收缩.扭曲和旋转 统一调整大小 我们经常会遇到一些我们希望转换为其他尺寸的图像. 我们可能想要扩大或缩小图像; 这两项任务都是由同一个功能完成的. cv::resize() 该cv::resiz ...
- [opencv]<学习Opencv>英文原版翻译学习
[注]下文全部内容为 <<Learning OpenCV 3: Computer Vision in C++ with the OpenCV Library>>经由在线翻译整理 ...
- pyhton:图像旋转
最近一个作业中要用到图像旋转,分享一下学习过程.如有讲错的地方,恳请指正! 图像旋转,想想真简单啊,不就是将图像矩阵乘上一个旋转平移矩阵就完了吗?实际上还真没这么简单.首先这个旋转平移矩阵怎么获得?通 ...
- OpenCV-Python Tutorials目录
版本 3.4.6 1 Introduction to OpenCV OpenCV介绍Learn how to setup OpenCV-Python on your computer! 2 Gui F ...
随机推荐
- 【jsp网站计数功能】 application session
在jsp页面中实现网站计数器的方法有很多,其中比较普遍的做法是利用application 和session对象.application对象可被所有用户共享:session是单用户共享,用户从访问系统开 ...
- php+redis实现电商秒杀功能
这一次总结和分享用Redis实现分布式锁来完成电商的秒杀功能.先扯点个人观点,之前我看了一篇博文说博客园的文章大部分都是分享代码,博文里强调说分享思路比分享代码更重要(貌似大概是这个意思,若有误请谅解 ...
- layer弹出层
最近因为项目要求做了一个layer弹出层demo,先看效果图 好了,现在开始上代码 index.jsp <%@ page language="java" import=&qu ...
- mysql 字段的类型有哪些
int型包括(tinyint, smallint, mediumint, int, bigint) tinyint是1个字节表达范围就是2的8次方(-128-128) 或者(0-255) 很多人不明白 ...
- Swift & OC 混编 浅析
转载自:http://www.infoq.com/cn/articles/wangyi-cartoon-swift-mixed-practice?utm_campaign=rightbar_v2&am ...
- 灵感闪现 篇 (一) 2d场景 3d 效果
中途打断一下 ,框架文档的 更新. 另开一篇主题为 灵感闪现的 板块. 在工作生活中,总有发现新事物或新东西 而让自己突然 灵感闪现的时候,那么这个时候,我必须要抓住,并尽快把 这份灵感实现下来. 之 ...
- pat L1-006. 连续因子
L1-006. 连续因子 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 一个正整数N的因子中可能存在若干连续的数字.例如630 ...
- UVALive 2324 Human Gene Functions(动态规划)
题意:求出将两个字符串改成一样长度所能形成最大的相似度. 思路:这个可以说是编辑距离的一个变形,编辑距离最终状态时要两个字符串完全一致,这个就是要求长度一样,而且这个只允许插入“—”这一个字符.模仿编 ...
- 学习笔记——装饰器模式Decorator
装饰器模式,最典型的例子. 工厂新开了流水线,生产了手机外壳,蓝天白云花色.刚准备出厂,客户说还要印奶牛在上面,WTF…… 时间上来不及,成本也不允许销毁了重来,怎么办?弄来一机器A,专门在蓝天白云的 ...
- 完整的 HTML 4 + HTML 5 实体参考手册
1 完整的 HTML 4 + HTML 5 实体参考手册 http://www.runoob.com/charsets/html-charsets.html 1 下表中的所有实体都能在所有的浏览器中正 ...