改变图像大小
//改变图像大小
void photoResize(const cv::Mat src, cv::Mat& dst, float size)
{
/**
* resize 实现图像改变大小
* src 原始图
* dst 目标图
* dsize 缩放后图片大小
**/
cv::resize(src, dst, cv::Size(src.cols / size, src.rows / size));
}
实现图像旋转
//实现图像旋转
void photoRotate(const cv::Mat src, cv::Mat& dst, int angle)
{
//定义中心点
cv::Point2f center = cv::Point2f(static_cast<float>(src.cols / 2.0), static_cast<float>(src.rows / 2.0));
/**
* getRotationMatrix2D 获得旋转矩阵,正角度是逆时针方向
* center 旋转中心点
* angle 旋转角度
* scale 图像缩放因子
**/
cv::Mat M = cv::getRotationMatrix2D(center, angle, 1.0);
/**
* warpAffine 仿射变换
* src 原始图
* dst 目标图
* M 转换矩阵
* size 输出图像大小
**/
cv::warpAffine(src, dst, M, src.size());
}
实现图像镜像翻转
void photoFlip(const cv::Mat src, cv::Mat& dst, int flipCode)
{
/**
* flip 翻转图像
* src 原始图
* dst 目标图
* flipCode 旋转方式
* 1代表水平方向(x-axis)旋转180度
* 0代表垂直方向(y-axis)旋转180度
* -1代表垂直和水平方向同时旋转
**/
cv::flip(src, dst, flipCode);
}
实现图像距离变换
距离变换可以把连通的区域分开
//实现图像距离变换
void photoDistanceTransform(const cv::Mat src, cv::Mat& dst)
{
/**
* distanceTransform 距离变换,针对二值化图像,可以根据距离变换的这个性质,经过简单的运算,用于细化字符的轮廓和查找物体质心(中心)
* src 原始图
* dst 目标图
* distanceType 距离计算方式
* DIST_USER = -1, //!< User defined distance
DIST_L1 = 1, //!< distance = |x1-x2| + |y1-y2|
DIST_L2 = 2, //!< the simple euclidean distance
DIST_C = 3, //!< distance = max(|x1-x2|,|y1-y2|)
DIST_L12 = 4, //!< L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1))
DIST_FAIR = 5, //!< distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998
DIST_WELSCH = 6, //!< distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846
DIST_HUBER = 7 //!< distance = |x|<c ? x^2/2 : c(|x|-c/2), c=1.345
* maskSize 掩模尺寸, 可取DIST_MASK_PRECISE或DIST_MASK_3, 5等
**/
cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY);
cv::threshold(dst, dst, 100, 255, cv::THRESH_OTSU);
cv::distanceTransform(dst, dst, cv::DIST_L2, cv::DIST_MASK_3);
cv::convertScaleAbs(dst, dst);
}
实现Log-polar变换
将图像像素坐标转换为极坐标,然后对距离取对数,
// 实现Log-polar变换
void photoLogPolar(const cv::Mat src, cv::Mat& dst)
{
/**
* logPolar 极坐标转换
* src 原始图
* dst 目标图
* center 极坐标中心
* M 掩模尺寸, 尺度参数--【值越大 离原点越近影响越大】
* flags cv::INTER_LINEAR插值算法
cv::WARP_FILL_OUTLIERS 超出图像边界区域如何处理
cv::WARP_INVERSE_MAP 未设置表示转换成极坐标(正变换 dst(phi,rho)<-src(x,y))
设置表示由极坐标变回直角坐标(逆变换 dst(x,y)<-src(phi,rho))
**/
cv::logPolar(src, dst, cv::Point2f(src.cols / 2, src.rows / 2), 50, cv::INTER_LINEAR + cv::WARP_FILL_OUTLIERS);
}
实现LinearPolar变换
// 实现LinearPolar变换
void photoLinearPolar(const cv::Mat src, cv::Mat& dst)
{
/**
* logPolar 极坐标为笛卡尔坐标系
* src 原始图
* dst 目标图
* center 极坐标中心
* M 掩模尺寸, 尺度参数--【值越大 离原点越近影响越大】
* flags cv::INTER_LINEAR插值算法
cv::WARP_FILL_OUTLIERS 超出图像边界区域如何处理
cv::WARP_INVERSE_MAP 未设置表示转换成极坐标(正变换 dst(phi,rho)<-src(x,y))
设置表示由极坐标变回直角坐标(逆变换 dst(x,y)<-src(phi,rho))
**/
cv::linearPolar(src, dst, cv::Point2f(src.cols / 2, src.rows / 2), 50, cv::INTER_LINEAR + cv::WARP_FILL_OUTLIERS);
}
实现灰度直方图均衡化
// 实现灰度直方图均衡化
void photoEqualizeHist(const cv::Mat src, cv::Mat& dst)
{
cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY);
cv::equalizeHist(dst, dst);
}
实现Hough变换
// 实现Hough变换
void photoHoughLinesP(const cv::Mat src, cv::Mat& dst)
{
cv::Mat cdst;
cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY);
/**
* Canny Canny边缘检测器
* image 源图像,灰度
* detected_edges 检测器的输出(可以与输入相同)
* threshold1 阈值1
* threshold2 阈值2
* apertureSize Sobel算子大小
**/
cv::Canny(dst, dst, 50, 150, 3);
cv::imshow("Canny", dst);
std::vector<cv::Vec4i> lines;
/**
* HoughLinesP 累计概率Hough变换
* dst 边缘检测器的输出。它应该是一个灰度图像(尽管事实上它是二进制的)
* lines 一个向量,将存储检测到的行的参数(r,θ)
* rho 参数的分辨率(以像素为单位)。我们使用1像素。r
* theta 以弧度表示的参数的分辨率。我们使用1度(CV_PI / 180)θ
* threshold 将“* detect *”一行的最小交点数
**/
cv::HoughLinesP(dst, lines, 1, CV_PI / 180, 10);
cv::cvtColor(dst, dst, cv::COLOR_GRAY2BGR);
//绘制线条显示结果
for (size_t i = 0; i < lines.size(); i++)
{
cv::Vec4i l = lines[i];
cv::line(dst, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(0,255,0), 1, cv::LINE_AA);
}
}
完整测试代码
/**
* 几何变换Demo
* 改变大小、旋转、镜像翻转、距离变换、Log-polar变换、灰度直方图均衡化、Hough变换
**/
#include <iostream>
#include <opencv2/opencv.hpp>
//实现图像改变大小
void photoResize(const cv::Mat src, cv::Mat& dst, float size)
{
/**
* resize 实现图像改变大小
* src 原始图
* dst 目标图
* dsize 缩放后图片大小
**/
cv::resize(src, dst, cv::Size(src.cols / size, src.rows / size));
}
//实现图像旋转
void photoRotate(const cv::Mat src, cv::Mat& dst, int angle)
{
//定义中心点
cv::Point2f center = cv::Point2f(static_cast<float>(src.cols / 2.0), static_cast<float>(src.rows / 2.0));
/**
* getRotationMatrix2D 获得旋转矩阵
* center 旋转中心点
* angle 旋转角度
* scale 图像缩放因子
**/
cv::Mat M = cv::getRotationMatrix2D(center, angle, 1.0);
/**
* warpAffine 仿射变换
* src 原始图
* dst 目标图
* M 转换矩阵
* size 输出图像大小
**/
cv::warpAffine(src, dst, M, src.size());
}
//实现图像镜像翻转
void photoFlip(const cv::Mat src, cv::Mat& dst, int flipCode)
{
/**
* flip 翻转图像
* src 原始图
* dst 目标图
* flipCode 旋转方式
* 1代表水平方向(x-axis)旋转180度
* 0代表垂直方向(y-axis)旋转180度
* -1代表垂直和水平方向同时旋转
**/
cv::flip(src, dst, flipCode);
}
//实现图像距离变换
void photoDistanceTransform(const cv::Mat src, cv::Mat& dst)
{
/**
* distanceTransform 距离变换
* src 原始图
* dst 目标图
* distanceType 距离计算方式, DIST_L1, DIST_L2或 DIST_C
* maskSize 掩模尺寸, 可取DIST_MASK_PRECISE或DIST_MASK_3, 5等
**/
cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY);
cv::threshold(dst, dst, 100, 255, cv::THRESH_OTSU);
cv::distanceTransform(dst, dst, cv::DIST_L2, cv::DIST_MASK_3);
cv::convertScaleAbs(dst, dst);
}
// 实现Log-polar变换
void photoLogPolar(const cv::Mat src, cv::Mat& dst)
{
/**
* logPolar 极坐标转换
* src 原始图
* dst 目标图
* center 极坐标中心
* M 掩模尺寸, 尺度参数--【值越大 离原点越近影响越大】
* flags cv::INTER_LINEAR插值算法
cv::WARP_FILL_OUTLIERS 超出图像边界区域如何处理
cv::WARP_INVERSE_MAP 未设置表示转换成极坐标(正变换 dst(phi,rho)<-src(x,y))
设置表示由极坐标变回直角坐标(逆变换 dst(x,y)<-src(phi,rho))
**/
cv::logPolar(src, dst, cv::Point2f(src.cols / 2, src.rows / 2), 50, cv::INTER_LINEAR + cv::WARP_FILL_OUTLIERS);
}
// 实现灰度直方图均衡化
void photoEqualizeHist(const cv::Mat src, cv::Mat& dst)
{
cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY);
cv::equalizeHist(dst, dst);
}
// 实现Hough变换
void photoHoughLinesP(const cv::Mat src, cv::Mat& dst)
{
cv::Mat cdst;
cv::cvtColor(src, dst, cv::COLOR_BGR2GRAY);
/**
* Canny Canny边缘检测器
* image 源图像,灰度
* detected_edges 检测器的输出(可以与输入相同)
* threshold1 阈值1
* threshold2 阈值2
* apertureSize Sobel算子大小
**/
cv::Canny(dst, dst, 50, 150, 3);
cv::imshow("Canny", dst);
std::vector<cv::Vec4i> lines;
/**
* HoughLinesP 累计概率Hough变换
* dst 边缘检测器的输出。它应该是一个灰度图像(尽管事实上它是二进制的)
* lines 一个向量,将存储检测到的行的参数(r,θ)
* rho 参数的分辨率(以像素为单位)。我们使用1像素。r
* theta 以弧度表示的参数的分辨率。我们使用1度(CV_PI / 180)θ
* threshold 将“* detect *”一行的最小交点数
**/
cv::HoughLinesP(dst, lines, 1, CV_PI / 180, 10);
cv::cvtColor(dst, dst, cv::COLOR_GRAY2BGR);
//绘制线条显示结果
for (size_t i = 0; i < lines.size(); i++)
{
cv::Vec4i l = lines[i];
cv::line(dst, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(0,255,0), 1, cv::LINE_AA);
}
}
int main()
{
//读入图片
std::string imagename = "Standard_image/lena.jpg";
cv::Mat img = cv::imread(imagename);
//如果读入图像失败
if (img.empty())
{
std::cout << "miss the image file : " + imagename << std::endl;
return -1;
}
cv::Mat resizeImg, rotateImg, flipImg, distanceTransformImg, logPolarImg;
cv::Mat equalizeHistImg, HoughLinesPImg;
photoResize(img, resizeImg, 0.8);
photoRotate(img, rotateImg, 45);
photoFlip(img, flipImg, -1);
photoDistanceTransform(img, distanceTransformImg);
photoLogPolar(img, logPolarImg);
photoEqualizeHist(img, equalizeHistImg);
photoHoughLinesP(img, HoughLinesPImg);
cv::imshow("原图", img);
cv::imshow("缩放", resizeImg);
cv::imshow("旋转", rotateImg);
cv::imshow("翻转", flipImg);
cv::imshow("距离变换", distanceTransformImg);
cv::imshow("极坐标变换", logPolarImg);
cv::imshow("直方图均衡化", equalizeHistImg);
cv::imshow("Hough变换", HoughLinesPImg);
cv::waitKey();
return 0;
}
测试结果
原始图像
等比例扩大1.25倍
旋转45°
上下左右都镜像翻转
Log-polar变换
灰度直方图均衡化
图像距离变换
Hough变换
canny
Hough变换(绿线)