这篇博文在写之前参考了网上的不少文章,感觉有的文章讲解比较到位,有的会误导人。
下面的代码运行结果已经和直接调用openclass="superseo">cv算子进行对比确保结果相同,就没有深究其开源代码了。
不过根据推断,opencv在实现resize图像插值时(1)需要做像素点中心对齐 *** 作;(2)不需要做copyMakeBorder边缘复制 *** 作。
原理参考:【图像处理】详解 最近邻插值、线性插值、双线性插值、双三次插值
其中双三次插值的实现参考了:C++ OpenCV实现图像双三次插值算法详解这篇文章原理讲的比较细,但代码实现有瑕疵。
- 最近邻插值
- 双线性插值
- 双三次插值
void nearest(cv::Mat& src, cv::Mat& dst, float sx, float sy)
{
//由缩放因子计算输出图像的尺寸(四舍五入)
dst = cv::Mat(round(src.rows * sy), round(src.cols * sx), src.type());
for (int i = 0; i < dst.rows; i++)
{
//几何中心对齐
float index_i = (i + 0.5) / sy - 0.5;
//防止越界
if (index_i < 0) index_i = 0;
if (index_i > src.rows - 1) index_i = src.rows - 1;
//取整
int i_index = round(index_i);
for (int j = 0; j < dst.cols; j++)
{
//几何中心对齐
float index_j = (j + 0.5) / sx - 0.5;
//防止越界
if (index_j < 0) index_j = 0;
if (index_j > src.cols - 1) index_j = src.cols - 1;
//取整
int j_index = round(index_j);
dst.at<uchar>(i, j) = src.at<uchar>(i_index, j_index);
}
}
}
双线性插值
void linear(Mat& src, Mat& dst, float sx, float sy)
{
dst = Mat(round(sy*src.rows), round(sx*src.cols), src.type());
for (int i = 0; i < dst.rows; i++)
{
//几何中心对齐
float index_i = (i + 0.5) / sy - 0.5;
//防止越界
if (index_i < 0) index_i = 0;
if (index_i > src.rows - 1) index_i = src.rows - 1;
//相邻4*4像素的行(坐标)
int i1 = floor(index_i);
int i2 = ceil(index_i);
//u为得到浮点型坐标行的小数部分
float u = index_i - i1;
for (int j = 0; j < dst.cols; j++)
{
//几何中心对齐
float index_j = (j + 0.5) / sx - 0.5;
//防止越界
if (index_j < 0) index_j = 0;
if (index_j > src.cols - 1) index_j = src.cols - 1;
//相邻4*4像素的列(坐标)
int j1 = floor(index_j);
int j2 = ceil(index_j);
//v为得到浮点型坐标列的小数部分
float v = index_j - j1;
dst.at<uchar>(i, j) = (1 - u)*(1 - v)*src.at<uchar>(i1, j1) + (1 - u)*v*src.at<uchar>(i1, j2) +
u*(1 - v)*src.at<uchar>(i2, j1) + u*v*src.at<uchar>(i2, j2);
}
}
}
双三次插值
vector<float> getWeight(float c, float a = -1.0)
{
//c就是u和v,横坐标和纵坐标的输出计算方式一样
vector<float> temp = { 1 + c, c, 1 - c, 2 - c };
//y(x) = (a+2)|x|^3- (a+3)|x|^2| + 1, |x|<=1
//y(x) = a|x|^3 - 5a|x|^2 + 8a|x| - 4a, 1<|x|<2
//y(x) = 0 1<|x|<2, otherwise
vector<float> weight(4);
weight[0] = a * pow(fabs(temp[0]), 3) - 5 * a * pow(fabs(temp[0]), 2) + 8 * a * fabs(temp[0]) - 4 * a;
weight[1] = (a + 2) * pow(fabs(temp[1]), 3) - (a + 3) * pow(fabs(temp[1]), 2) + 1;
weight[2] = (a + 2) * pow(fabs(temp[2]), 3) - (a + 3) * pow(fabs(temp[2]), 2) + 1;
weight[3] = a * pow(fabs(temp[3]), 3) - 5 * a * pow(fabs(temp[3]), 2) + 8 * a * fabs(temp[3]) - 4 * a;
return weight;
}
void bicubic(Mat& src, Mat& dst, float sx, float sy)
{
int dst_cols = sx*src.cols, dst_rows = sy*src.rows;
dst.create(dst_rows, dst_cols, src.type());
for (int i = 0; i < dst_rows; ++i)
{
float index_i = (i + 0.5) / sy - 0.5; //做了几何中心对齐
if (index_i < 0) index_i = 0;
if (index_i > src.rows - 1) index_i = src.rows - 1;
//目标图像点坐标对应原图点坐标的4个纵坐标
int i0 = index_i - 1, i1 = index_i, i2 = index_i + 1, i3 = index_i + 2;
float u = index_i - i1;
vector<float> weight_u = getWeight(u);
for (int j = 0; j < dst_cols; ++j)
{
float index_j = (j + 0.5) / sx - 0.5;
if (index_j < 0) index_j = 0;
if (index_j > src.cols - 1) index_j = src.cols - 1;
//目标图像点坐标对应原图点坐标的4个横坐标
int j0 = index_j - 1, j1 = index_j, j2 = index_j + 1, j3 = index_j + 2;
float v = index_j - j1;
vector<float> weight_v = getWeight(v);
//目标点像素对应原图点像素周围4x4区域的加权计算(插值)
float temp = 0;
for (int s = 0; s <= 3; s++)
{
for (int t = 0; t <= 3; t++)
{
temp += src.at<uchar>(i1 + s - 1, j1 + t - 1)*weight_u[s] * weight_v[t];
}
}
if (temp < 0) temp = 0;
if (temp > 255) temp = 255;
dst.at<uchar>(i, j) = temp;
}
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)