当前位置:   article > 正文

opencv 插值方式_opencv 像素灰度值的插值方法 海康威视

opencv 像素灰度值的插值方法 海康威视

一、插值方式与resize()的关系

resize()函数里面包含插值的几种方式:

  1. void resize(InputArray src,//输入,原图像,即待改变大小的图像;
  2. OutputArray dst, //输出,改变大小之后的图像,这个图像和原图像具有相同的内容,只是大小和原图像不一样而已;
  3. Size dsize, //输出图像的大小。如果这个参数不为0,那么就代表将原图像缩放到这个Size(width,height)指定的大小;如果这个参数为0,那么原图像缩放之后的大小就要通过下面的公式来计算:
  4. double fx=0, // width方向的缩放比例,如果它是0,那么它就会按照(double)dsize.width/src.cols来计算;
  5. double fy=0, //height方向的缩放比例,如果它是0,那么它就会按照(double)dsize.height/src.rows来计算;
  6. int interpolation=INTER_LINEAR// 这个是指定插值的方式,图像缩放之后,肯定像素要进行重新计算的,就靠这个参数来指定重新计算像素的方式,有以下几种:
  7. INTER_NEAREST - 最邻近插值
  8. INTER_LINEAR - 双线性插值,如果最后一个参数你不指定,默认使用这种方法
  9. INTER_AREA -区域插值 resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method.
  10. INTER_CUBIC - 4x4像素邻域内的双立方插值
  11. INTER_LANCZOS4 - 8x8像素邻域内的Lanczos插值
  12. );
  13. 使用注意事项:
  14. dsize和fx/fy不能同时为0

 

 

二、近邻插值INTER_NEAREST

最近邻插值法, 找到与之距离最相近的邻居(原来就存在的像素点, 黑点), 赋值与其相同。

实现opencv中常用的三种插值算法 - 简书 

 

  1. //最近邻域插值
  2. //根据目标图像的像素点(浮点坐标)找到原始图像中的4个像素点,取距离该像素点最近的一个原始像素值作为该点的值。
  3. #include<opencv2/opencv.hpp>
  4. #include<cassert>
  5. namespace mycv {
  6. void nearestIntertoplation(cv::Mat& src, cv::Mat& dst, const int rows, const int cols);
  7. }//mycv
  8. double distance(const double x1, const double y1, const double x2, const double y2);//两点之间距离,这里用欧式距离
  9. int main()
  10. {
  11. cv::Mat img = cv::imread("lena.jpg", 0);
  12. if (img.empty()) return -1;
  13. cv::Mat dst;
  14. mycv::nearestIntertoplation(img, dst, 600, 600);
  15. cv::imshow("img", img);
  16. cv::imshow("dst", dst);
  17. cv::waitKey(0);
  18. return 0;
  19. return 0;
  20. }//main
  21. void mycv::nearestIntertoplation(cv::Mat& src, cv::Mat& dst, const int rows, const int cols)
  22. {
  23. //比例尺
  24. const double scale_row = static_cast<double>(src.rows) / rows;
  25. const double scale_col = static_cast<double>(src.rows) / cols;
  26. //扩展src到dst
  27. dst = cv::Mat(rows, cols, src.type());
  28. assert(src.channels() == 1 && dst.channels() == 1);
  29. for (int i = 0; i < rows; ++i)//dst的行
  30. for (int j = 0; j < cols; ++j)//dst的列
  31. {
  32. //求插值的四个点
  33. double y = (i + 0.5) * scale_row + 0.5;
  34. double x = (j + 0.5) * scale_col + 0.5;
  35. int x1 = static_cast<int>(x);//col对应x
  36. if (x1 >= (src.cols - 2)) x1 = src.cols - 2;//防止越界
  37. int x2 = x1 + 1;
  38. int y1 = static_cast<int>(y);//row对应y
  39. if (y1 >= (src.rows - 2)) y1 = src.rows - 2;
  40. int y2 = y1 + 1;
  41. //根据目标图像的像素点(浮点坐标)找到原始图像中的4个像素点,取距离该像素点最近的一个原始像素值作为该点的值。
  42. assert(0 < x2 && x2 < src.cols && 0 < y2 && y2 < src.rows);
  43. std::vector<double> dist(4);
  44. dist[0] = distance(x, y, x1, y1);
  45. dist[1] = distance(x, y, x2, y1);
  46. dist[2] = distance(x, y, x1, y2);
  47. dist[3] = distance(x, y, x2, y2);
  48. int min_val = dist[0];
  49. int min_index = 0;
  50. for (int i = 1; i < dist.size(); ++i)
  51. if (min_val > dist[i])
  52. {
  53. min_val = dist[i];
  54. min_index = i;
  55. }
  56. switch (min_index)
  57. {
  58. case 0:
  59. dst.at<uchar>(i, j) = src.at<uchar>(y1, x1);
  60. break;
  61. case 1:
  62. dst.at<uchar>(i, j) = src.at<uchar>(y1, x2);
  63. break;
  64. case 2:
  65. dst.at<uchar>(i, j) = src.at<uchar>(y2, x1);
  66. break;
  67. case 3:
  68. dst.at<uchar>(i, j) = src.at<uchar>(y2, x2);
  69. break;
  70. default:
  71. assert(false);
  72. }
  73. }
  74. }
  75. double distance(const double x1, const double y1, const double x2, const double y2)//两点之间距离,这里用欧式距离
  76. {
  77. return (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2);//只需比较大小,返回距离平方即可
  78. }

 三、线性插值

已知两点(红色) ,在给出一个蓝点的x坐标, 求y。

 

  1. //线性内插(双线性插值)
  2. #include<opencv2/opencv.hpp>
  3. #include<opencv2/core/matx.hpp>
  4. #include<cassert>
  5. namespace mycv {
  6. void bilinearIntertpolatioin(cv::Mat& src, cv::Mat& dst, const int rows, const int cols);
  7. }//mycv
  8. int main()
  9. {
  10. cv::Mat img = cv::imread("lena.jpg", 0);
  11. if (img.empty()) return -1;
  12. cv::Mat dst;
  13. mycv::bilinearIntertpolatioin(img, dst, 600, 600);
  14. cv::imshow("img", img);
  15. cv::imshow("dst", dst);
  16. cv::waitKey(0);
  17. return 0;
  18. }//main
  19. void mycv::bilinearIntertpolatioin(cv::Mat& src, cv::Mat& dst, const int rows, const int cols)
  20. {
  21. //比例尺
  22. const double scale_row = static_cast<double>(src.rows) / rows;
  23. const double scale_col = static_cast<double>(src.rows) / cols;
  24. //扩展src到dst
  25. dst = cv::Mat(rows, cols, src.type());
  26. assert(src.channels() == 1 && dst.channels() == 1);
  27. for(int i = 0; i < rows; ++i)//dst的行
  28. for (int j = 0; j < cols; ++j)//dst的列
  29. {
  30. //求插值的四个点
  31. double y = (i + 0.5) * scale_row + 0.5;
  32. double x = (j + 0.5) * scale_col + 0.5;
  33. int x1 = static_cast<int>(x);//col对应x
  34. if (x1 >= (src.cols - 2)) x1 = src.cols - 2;//防止越界
  35. int x2 = x1 + 1;
  36. int y1 = static_cast<int>(y);//row对应y
  37. if (y1 >= (src.rows - 2)) y1 = src.rows - 2;
  38. int y2 = y1 + 1;
  39. assert(0 < x2 && x2 < src.cols && 0 < y2 && y2 < src.rows);
  40. //插值公式,参考维基百科矩阵相乘的公式https://zh.wikipedia.org/wiki/%E5%8F%8C%E7%BA%BF%E6%80%A7%E6%8F%92%E5%80%BC
  41. cv::Matx12d matx = { x2 - x, x - x1 };
  42. cv::Matx22d matf = { static_cast<double>(src.at<uchar>(y1, x1)), static_cast<double>(src.at<uchar>(y2, x1)),
  43. static_cast<double>(src.at<uchar>(y1, x2)), static_cast<double>(src.at<uchar>(y2, x2)) };
  44. cv::Matx21d maty = {
  45. y2 - y,
  46. y - y1
  47. };
  48. auto val = (matx * matf * maty);
  49. dst.at<uchar>(i, j) = val(0,0);
  50. }
  51. }

四、双三次插值

在数值分析这个数学分支中,双三次插值(英语:Bicubic interpolation)是二维空间中最常用的插值方法。在这种方法中,函数 f 在点 (x, y) 的值可以通过矩形网格中最近的十六个采样点的加权平均得到,在这里需要使用两个多项式插值三次函数,每个方向使用一个

双三次插值计算公式
 

 

 

那么这个a(i, j)便是介绍里面所说的加权系数了,所以关键是要把它求解出来。

求解加权系数的公式如下

 

  1. 求解加强系数代码如下:
  2. std::vector<double> mycv::getW(double coor, double a)
  3. {
  4. std::vector<double> w(4);
  5. int base = static_cast<int>(coor);//取整作为基准
  6. double e = coor - static_cast<double>(base);//多出基准的小数部分
  7. std::vector<double> tmp(4);//存放公式中 |x| <= 1, 1 < |x| < 2四个值
  8. // 4 x 4的16个点,所以tmp[0]和tmp[4]距离较远,值在[1, 2]区间
  9. tmp[0] = 1.0 + e;// 1 < x < 2
  10. tmp[1] = e;//x <= 1
  11. tmp[2] = 1.0 - e;// x <= 1
  12. tmp[3] = 2.0 - e;// 1 < x < 2
  13. //按照bicubic公式计算系数w
  14. // x <= 1
  15. w[1] = (a + 2.0) * std::abs(std::pow(tmp[1], 3)) - (a + 3.0) * std::abs(std::pow(tmp[1], 2)) + 1;
  16. w[2] = (a + 2.0) * std::abs(std::pow(tmp[2], 3)) - (a + 3.0) * std::abs(std::pow(tmp[2], 2)) + 1;
  17. // 1 < x < 2
  18. w[0] = a * std::abs(std::pow(tmp[0], 3)) - 5.0 * a * std::abs(std::pow(tmp[0], 2)) + 8.0*a*std::abs(tmp[0]) - 4.0*a;
  19. w[3] = a * std::abs(std::pow(tmp[3], 3)) - 5.0 * a * std::abs(std::pow(tmp[3], 2)) + 8.0*a*std::abs(tmp[3]) - 4.0*a;
  20. return w;
  21. }
  22. 求解出来之后,wx和wy就是4x4组成的16个系数,与插值所需要用到4x4的16个点相匹配。插值步骤的关键代码
  23. //4x4数量的点(rr, cc) -> (y, x)
  24. std::vector<std::vector<int> > src_arr = {
  25. { src.at<uchar>(rr - 1, cc - 1), src.at<uchar>(rr, cc - 1), src.at<uchar>(rr + 1, cc - 1), src.at<uchar>(rr + 2, cc - 1)},
  26. { src.at<uchar>(rr - 1, cc), src.at<uchar>(rr, cc), src.at<uchar>(rr + 1, cc), src.at<uchar>(rr + 2, cc)},
  27. { src.at<uchar>(rr - 1, cc + 1), src.at<uchar>(rr, cc + 1), src.at<uchar>(rr + 1, cc + 1), src.at<uchar>(rr + 2, cc + 1)},
  28. { src.at<uchar>(rr - 1, cc + 2), src.at<uchar>(rr, cc + 2), src.at<uchar>(rr + 1, cc + 2), src.at<uchar>(rr + 2, cc + 2)}
  29. };
  30. for(int p = 0; p < 3; ++p)
  31. for (int q = 0; q < 3; ++q)
  32. {
  33. //val(p, q) = w(p,q) * src(p, q)
  34. val += wr[p] * wc[q] * static_cast<double>(src_arr[p][q]);
  35. }
  36. assert(i < dst.rows && j < dst.cols);
  37. dst.at<uchar>(i, j) = static_cast<int>(val);
  38. //双三次插值
  39. #include<opencv2/opencv.hpp>
  40. #include<iostream>
  41. #include<vector>
  42. #include<cassert>
  43. namespace mycv {
  44. void bicubicInsterpolation(cv::Mat& src, cv::Mat& dst, const int rows, const int cols);
  45. std::vector<double> getW(double coor, double a = -0.5);//a默认-0.5
  46. }//mycv
  47. int main(void)
  48. {
  49. cv::Mat img = cv::imread("lena.jpg", 0);
  50. if (img.empty()) return -1;
  51. cv::Mat dst;
  52. mycv::bicubicInsterpolation(img, dst, 600, 600);
  53. cv::imshow("img", img);
  54. cv::imshow("dst", dst);
  55. cv::waitKey(0);
  56. return 0;
  57. }//main
  58. void mycv::bicubicInsterpolation(cv::Mat& src, cv::Mat& dst, const int rows, const int cols)
  59. {
  60. dst = cv::Mat(rows, cols, src.type(), cv::Scalar::all(0));//初始化dst
  61. //比例尺
  62. double row_scale = static_cast<double>(src.rows) / rows;
  63. double col_scale = static_cast<double>(src.cols) / cols;
  64. switch (src.channels())
  65. {
  66. case 1://灰度
  67. for(int i = 2; i < dst.rows - 2; ++i)
  68. for (int j = 2; j < dst.cols - 2; ++j)
  69. {
  70. //计算系数w
  71. double r = static_cast<double>(i * row_scale);
  72. double c = static_cast<double>(j * col_scale);
  73. //防止越界
  74. if (r < 1.0) r += 1.0;
  75. if (c < 1.0) c += 1.0;
  76. std::vector<double> wr = mycv::getW( r);
  77. std::vector<double> wc = mycv::getW( c);
  78. //最后计算插值得到的灰度值
  79. double val = 0;
  80. int cc = static_cast<int>(c);
  81. int rr = static_cast<int>(r);
  82. //防止越界
  83. if (cc > src.cols - 3)
  84. {
  85. cc = src.cols - 3;
  86. }
  87. if (rr > src.rows - 3) rr = src.rows - 3;
  88. assert(0 <= (rr - 1) && 0 <= (cc - 1) && (rr + 2) < src.rows && (cc + 2) < src.cols);
  89. //4x4数量的点(rr, cc) -> (y, x)
  90. std::vector<std::vector<int> > src_arr = {
  91. { src.at<uchar>(rr - 1, cc - 1), src.at<uchar>(rr, cc - 1), src.at<uchar>(rr + 1, cc - 1), src.at<uchar>(rr + 2, cc - 1)},
  92. { src.at<uchar>(rr - 1, cc), src.at<uchar>(rr, cc), src.at<uchar>(rr + 1, cc), src.at<uchar>(rr + 2, cc)},
  93. { src.at<uchar>(rr - 1, cc + 1), src.at<uchar>(rr, cc + 1), src.at<uchar>(rr + 1, cc + 1), src.at<uchar>(rr + 2, cc + 1)},
  94. { src.at<uchar>(rr - 1, cc + 2), src.at<uchar>(rr, cc + 2), src.at<uchar>(rr + 1, cc + 2), src.at<uchar>(rr + 2, cc + 2)}
  95. };
  96. for(int p = 0; p < 3; ++p)
  97. for (int q = 0; q < 3; ++q)
  98. {
  99. //val(p, q) = w(p,q) * src(p, q)
  100. val += wr[p] * wc[q] * static_cast<double>(src_arr[p][q]);
  101. }
  102. assert(i < dst.rows && j < dst.cols);
  103. dst.at<uchar>(i, j) = static_cast<int>(val);
  104. }
  105. break;
  106. case 3://彩色(原理一样多了两个通道而已)
  107. break;
  108. default:
  109. break;
  110. }
  111. }
  112. std::vector<double> mycv::getW(double coor, double a)
  113. {
  114. std::vector<double> w(4);
  115. int base = static_cast<int>(coor);//取整作为基准
  116. double e = coor - static_cast<double>(base);//多出基准的小数部分
  117. std::vector<double> tmp(4);//存放公式中 |x| <= 1, 1 < |x| < 2四个值
  118. // 4 x 4的16个点,所以tmp[0]和tmp[4]距离较远,值在[1, 2]区间
  119. tmp[0] = 1.0 + e;// 1 < x < 2
  120. tmp[1] = e;//x <= 1
  121. tmp[2] = 1.0 - e;// x <= 1
  122. tmp[3] = 2.0 - e;// 1 < x < 2
  123. //按照bicubic公式计算系数w
  124. // x <= 1
  125. w[1] = (a + 2.0) * std::abs(std::pow(tmp[1], 3)) - (a + 3.0) * std::abs(std::pow(tmp[1], 2)) + 1;
  126. w[2] = (a + 2.0) * std::abs(std::pow(tmp[2], 3)) - (a + 3.0) * std::abs(std::pow(tmp[2], 2)) + 1;
  127. // 1 < x < 2
  128. w[0] = a * std::abs(std::pow(tmp[0], 3)) - 5.0 * a * std::abs(std::pow(tmp[0], 2)) + 8.0*a*std::abs(tmp[0]) - 4.0*a;
  129. w[3] = a * std::abs(std::pow(tmp[3], 3)) - 5.0 * a * std::abs(std::pow(tmp[3], 2)) + 8.0*a*std::abs(tmp[3]) - 4.0*a;
  130. return w;
  131. }

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号