• opencv之图像翻转、平移、缩放、旋转、仿射学习笔记


    opencv版本:opencv3.4.1

     

    目录

    1. 图像翻转(坐标映射)

    2.  平移

     3. 缩放

    4. 旋转


    1. 图像翻转(坐标映射)

    1. int main()
    2. {
    3. cv::Mat srcImage = cv::imread("./lena.jpg");
    4. if(!srcImage.data){
    5. return -1;
    6. }
    7. int rows = srcImage.rows;
    8. int cols = srcImage.cols;
    9. //输出矩阵定义
    10. cv::Mat resultImage(rows, cols, srcImage.type());
    11. //x与y方向的矩阵
    12. cv::Mat xMapImage(rows, cols, CV_32FC1);
    13. cv::Mat yMapImage(rows, cols, CV_32FC1);
    14. //图像遍历
    15. for(int r = 0; r < rows; r++){
    16. for(int c = 0; c < cols; c++){
    17. //x与y均翻转
    18. xMapImage.at<float>(r,c) = cols-c;
    19. yMapImage.at<float>(r,c) = rows-r;
    20. }
    21. }
    22. remap(srcImage, resultImage, xMapImage, yMapImage, CV_INTER_LINEAR, cv::BORDER_CONSTANT,Scalar(0,0,0));
    23. cv::imwrite("resultImage.jpg", resultImage);
    24. }

    效果:

    2.  平移

     有两种情况,(a)平移时图像大小保持不变; (b)平移时图像大小变化;

    1. //平移不改变图像
    2. //参数:平移的图像,平移的x和y偏移量;
    3. cv::Mat imageTranslateNoChange(cv::Mat &srcImage, int xOffset, int yOffset)
    4. {
    5. int nRows = srcImage.rows;
    6. int nCols = srcImage.cols;
    7. cv::Mat resultImage(nRows, nCols, srcImage.type());
    8. //遍历图像
    9. for(int r = 0 ; r < nRows; r++){
    10. for(int c = 0; c < nCols; c++){
    11. int x = c - xOffset;
    12. int y = r - yOffset;
    13. //边界判断;
    14. if(x >= 0 && y >= 0 && x < nCols && y < nRows){
    15. resultImage.at(r, c) = srcImage.ptr(y)[x];
    16. }
    17. }
    18. }
    19. return resultImage;
    20. }
    21. //平移,会改变图像
    22. cv::Mat imageTranslateChange(cv::Mat &srcImage, int xOffset, int yOffset)
    23. {
    24. int nRows = srcImage.rows + abs(yOffset);//加上y
    25. int nCols = srcImage.cols + abs(xOffset);//加上x
    26. cv::Mat resultImage(nRows, nCols, srcImage.type());
    27. //遍历图像
    28. for(int r = 0 ; r < nRows; r++){
    29. for(int c = 0; c < nCols; c++){
    30. int x = c - xOffset;
    31. int y = r - yOffset;
    32. //边界判断;
    33. if(x >= 0 && y >= 0 && x < nCols && y < nRows){
    34. resultImage.at(r, c) = srcImage.ptr(y)[x];
    35. }
    36. }
    37. }
    38. return resultImage;
    39. }
    40. int main()
    41. {
    42. cv::Mat srcImage = cv::imread("./lena.jpg");
    43. if(!srcImage.data){
    44. return -1;
    45. }
    46. //cv::Mat resultImage = imageTranslateNoChange(srcImage, 200, 50);
    47. //cv::imwrite("translateNoChange.jpg", resultImage);
    48. cv::Mat resultImage = imageTranslateChange(srcImage, 80, 80);
    49. cv::imwrite("translateChange.jpg", resultImage);
    50. return 0;
    51. }

    效果:

     3. 缩放

    1. //等间隔提取图像缩放
    2. cv::Mat imageEquidistant(cv::Mat& srcImage, float kx, float ky)
    3. {
    4. //获取输出图像分辨率
    5. int nRows = cvRound(srcImage.rows * kx);
    6. int nCols = cvRound(srcImage.cols * ky);
    7. cv::Mat resultImage(nRows, nCols, srcImage.type());
    8. for(int i = 0; i < nRows; ++i){
    9. for(int j = 0; j < nCols; ++j){
    10. //根据水平因子计算坐标
    11. int x = static_cast<int>((i+1)/kx+0.5)-1;
    12. //根据垂直因子计算坐标
    13. int y = static_cast<int>((j+1)/ky+0.5)-1;
    14. resultImage.at(i, j) = srcImage.at(x,y);
    15. }
    16. }
    17. return resultImage;
    18. }
    19. static cv::Vec3b areaAverage(cv::Mat& srcImage, Point_<int> leftPoint, Point_<int> rightPoint)
    20. {
    21. int temp1 = 0, temp2=0, temp3=0;
    22. //计算区域子块像素点个数
    23. int nPix = (rightPoint.x - leftPoint.x) * (rightPoint.y - leftPoint.y);
    24. //对区域子块各个通道对像素求和
    25. for(int i = leftPoint.x; i < rightPoint.x ;++i){
    26. for(int j = leftPoint.y; j < rightPoint.y; ++j){
    27. temp1 += srcImage.at(i,j)[0];
    28. temp2 += srcImage.at(i,j)[1];
    29. temp3 += srcImage.at(i,j)[2];
    30. }
    31. }
    32. //对每个通道求均值
    33. Vec3b vecTemp;
    34. vecTemp[0] = temp1 / nPix;
    35. vecTemp[1] = temp2 / nPix;
    36. vecTemp[2] = temp3 / nPix;
    37. return vecTemp;
    38. }
    39. //基于子块提取图像缩放
    40. cv::Mat imageRegionSubBlock(cv::Mat& srcImage, double kx, double ky)
    41. {
    42. //获取输出图像分辨率
    43. int nRows = cvRound(srcImage.rows * kx);
    44. int nCols = cvRound(srcImage.cols * ky);
    45. cv::Mat resultImage(nRows, nCols, srcImage.type());
    46. //区域子块的左上角行列坐标
    47. int leftRowCoordinate = 0;
    48. int leftColCoordinate = 0;
    49. for(int i = 0; i < nRows; ++i){
    50. //根据水平因子计算坐标
    51. int x = static_cast<int>((i+1)/kx+0.5)-1;
    52. for(int j = 0; j < nCols; ++j){
    53. //根据垂直因子计算坐标
    54. int y = static_cast<int>((j+1)/ky+0.5)-1;
    55. //求解区域子块的均值;
    56. resultImage.at(i, j) = areaAverage(srcImage,Point_<int>(leftRowCoordinate,leftColCoordinate),Point_<int>(x,y));
    57. //更新子块左上角的列坐标
    58. leftColCoordinate = y + 1;
    59. }
    60. leftColCoordinate = 0;
    61. //更新子块左上角的行坐标
    62. leftRowCoordinate = x + 1;
    63. }
    64. return resultImage;
    65. }
    1. int main()
    2. {
    3. cv::Mat srcImage = cv::imread("./lena.jpg");
    4. if(!srcImage.data){
    5. return -1;
    6. }
    7. cv::Mat resultImage;
    8. //resultImage = imageEquidistant(srcImage, 0.5, 0.5);
    9. resultImage = imageRegionSubBlock(srcImage, 0.5, 0.5);
    10. cv::imwrite("RegionSubBlock.jpg", resultImage);
    11. return 0;
    12. }

    效果: 

    4. 旋转

    1. cv::Mat imageRotate(cv::Mat& srcImage, int angle)
    2. {
    3. //角度转换
    4. float alpha = angle * CV_PI / 180;
    5. //构造旋转矩阵
    6. float rotateMat[3][3] = {
    7. {cos(alpha), -sin(alpha), 0},
    8. {sin(alpha), cos(alpha), 0},
    9. {0 , 0, 1}
    10. };
    11. int nSrcRows = srcImage.rows;
    12. int nSrcCols = srcImage.cols;
    13. //计算旋转后图像矩阵的各个顶点位置
    14. float a1 = nSrcCols * rotateMat[0][0] ;
    15. float b1 = nSrcCols * rotateMat[1][0] ;
    16. float a2 = nSrcCols * rotateMat[0][0] + nSrcRows * rotateMat[0][1];
    17. float b2 = nSrcCols * rotateMat[1][0] + nSrcRows * rotateMat[1][1];;
    18. float a3 = nSrcRows * rotateMat[0][1] ;
    19. float b3 = nSrcRows * rotateMat[1][1] ;
    20. int kxMin = min(min(min(0.0f,a1),a2),a3);
    21. int kxMax = max(max(max(0.0f,a1),a2),a3);
    22. int kyMin = min(min(min(0.0f,b1),b2),b3);
    23. int kyMax = max(max(max(0.0f,b1),b2),b3);
    24. //计算输出矩阵的尺寸
    25. int nRows = abs(kxMax - kxMin);
    26. int nCols = abs(kyMax - kyMin);
    27. cv::Mat dst(nRows, nCols, srcImage.type(), cv::Scalar::all(0));
    28. for(int i = 0; i < nRows; ++i){
    29. for(int j = 0 ; j < nCols; ++j){
    30. //旋转坐标转换
    31. int x = (j + kxMin) * rotateMat[0][0] - (i + kyMin) * rotateMat[0][1];
    32. int y = -(j + kxMin) * rotateMat[1][0] + (i + kyMin) * rotateMat[1][1];
    33. //区域旋转
    34. if((x >= 0) && (x < nSrcCols) && (y >= 0) && y < nSrcRows){
    35. dst.at(i, j) = srcImage.at(y,x);
    36. }
    37. }
    38. }
    39. return dst;
    40. }

    4.1 旋转30和60度

    1. int main()
    2. {
    3. cv::Mat srcImage = cv::imread("./lena.jpg");
    4. if(!srcImage.data){
    5. return -1;
    6. }
    7. cv::Mat resultImage;
    8. //resultImage = imageRotate(srcImage,30);
    9. resultImage = imageRotate(srcImage,60);
    10. cv::imwrite("rotate60.jpg", resultImage);
    11. return 0;
    12. }

    效果:

            图像翻转是图像旋转的特例,opencv中提供了traspose与filp函数对图像进行矩阵转置变换;可以将图像进行水平或垂直翻转;

    4.2 图像翻转

    1. int main()
    2. {
    3. cv::Mat srcImage = cv::imread("./lena.jpg");
    4. if(!srcImage.data){
    5. return -1;
    6. }
    7. cv::Mat resultImage;
    8. //transpose(srcImage, resultImage);//逆时针旋转90;
    9. //flip( srcImage, resultImage, 0); //垂直翻转
    10. //flip( srcImage, resultImage, 1); //水平翻转
    11. //flip( srcImage, resultImage, -1);//垂直和水平翻转
    12. cv::imwrite("flip-1.jpg", resultImage);
    13. return 0;
    14. }

     效果:

    5. 仿射变换

    1. int main()
    2. {
    3. cv::Mat srcImage = cv::imread("./lena.jpg");
    4. if(!srcImage.data){
    5. return -1;
    6. }
    7. int nRows = srcImage.rows;
    8. int nCols = srcImage.cols;
    9. //定义仿射变换的二维点数组
    10. //源图像和目标图像对应映射的三个点
    11. cv::Point2f srcPoint[3];
    12. cv::Point2f resPoint[3];
    13. srcPoint[0] = cv::Point2f(0, 0);
    14. srcPoint[1] = cv::Point2f(nCols-1, 0);
    15. srcPoint[2] = cv::Point2f(0,nRows-1);
    16. resPoint[0] =cv::Point2f(nCols*0, nRows*0.33);
    17. resPoint[1] =cv::Point2f(nCols*0.85, nRows*0.25);
    18. resPoint[2] =cv::Point2f(nCols*0.15, nRows*0.7);
    19. //定义仿射变换矩阵
    20. cv::Mat warpMat(cv::Size(2,3), CV_32F);
    21. cv::Mat resultImage;
    22. cv::Mat::zeros(nRows, nCols, srcImage.type());
    23. //计算仿射变换矩阵,即仿射变换的2x3数组
    24. warpMat = cv::getAffineTransform(srcPoint, resPoint);
    25. //根据仿射矩阵计算图像仿射变换
    26. cv::warpAffine(srcImage, resultImage, warpMat, cv::Size(resultImage.rows,resultImage.cols));
    27. cv::imwrite("warpAffine.jpg", resultImage);
    28. #if 1
    29. //设置仿射变换参数
    30. cv::Point2f centerPoint = cv::Point2f(nCols/2, nRows/2);
    31. double angle = -50;
    32. double scale = 0.7;
    33. //获取仿射变换矩阵
    34. warpMat = getRotationMatrix2D(centerPoint, angle, scale);
    35. //对源图像进行角度仿射变换
    36. cv::warpAffine(srcImage, resultImage, warpMat, cv::Size(resultImage.rows,resultImage.cols));
    37. #endif
    38. cv::imwrite("warpAffine-angle.jpg", resultImage);
    39. return 0;
    40. }

     效果:

  • 相关阅读:
    node+vue3+mysql前后分离开发范式——实现视频文件上传并渲染
    自学软件测试?一般人我还是劝你算了吧...
    API是什么&API管理存在哪些问题,如何解决?
    智慧住建工程项目监管数字化管理解决方案
    maya 设置半径 获取时长,设置时长
    Windows下Redis3.0集群搭建
    OTA: Optimal Transport Assignment for Object Detection 论文和代码学习
    一、synchronized详解与锁升级
    【业务功能篇91】微服务-springcloud-多线程-线程池执行顺序
    伦敦银最新走势不利怎么办
  • 原文地址:https://blog.csdn.net/qq_39048131/article/details/126321572