双线性插值_亚像素边缘尺寸测量
程序员文章站
2024-03-16 22:57:16
...
读了好几篇关于亚像素边缘的博客,记录几点收获总结,若有错,还请读者朋友指正。
- 亚像素边缘常见的方法主要是插值法和拟合法,如:近邻插值、双线性插值、三次插值、最小二乘法拟合等。
- 实际并不存在亚像素边缘坐标,可以通过放大或缩小图像获得原图像的亚像素位置在新图像中的展示。
- 尺寸测量时新图像的像素距离除以缩放比例即可获得原图像的亚像素精度的距离。
感谢博主萱子子子的插值代码。本文使用霍夫直线检测,简单通过直线尺寸测量进行了验证。
代码如下:
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace cv;
using namespace std;
Mat LinerInter(Mat &srcImage, double kx, double ky);
int main()
{
Mat src = imread("D:/images/chazhi.jpg");
Mat result = LinerInter(src,1.2,1.2);
Mat srcImg, gray, binary;
cvtColor(src, gray, COLOR_BGR2GRAY);
threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_OTSU);
Canny(binary, srcImg, 10, 200, 3);
Mat gray_1, resultImg,binary_1;
cvtColor(result, gray_1, COLOR_BGR2GRAY);
threshold(gray_1, binary_1, 0, 255, THRESH_BINARY | THRESH_OTSU);
Canny(binary_1, resultImg, 10, 200, 3);
//直线距离
vector<Vec4i> lines, lines_1;
vector<float> dis, dis_1;
HoughLinesP(srcImg, lines, 1, CV_PI / 180, 150, 30, 10);
HoughLinesP(resultImg, lines_1, 1, CV_PI / 180, 150, 30, 10);
//【7】迭代器遍历向量,line()函数绘制线段
for (int i = 0; i < lines.size(); i++) {
//插值前
Point2i pt1(lines[i][0], lines[i][1]);
Point2i pt2(lines[i][2], lines[i][3]);
//cout << lines[i][0] << " " << lines[i][1] << " " << lines[i][2] << " " << lines[i][3] << endl;
dis.push_back(sqrt(abs((pt1.x - pt2.x)) * abs((pt1.x - pt2.x)) + abs((pt1.y - pt2.y)) * abs((pt1.y - pt2.y))));
line(src, pt1, pt2, Scalar(0, 0, 255), 1, LINE_AA);
}
//cout << lines_1.size() << endl;
for (int i = 0; i < lines_1.size(); i++) {
//插值后
Point2i pt1_1(lines_1[i][0], lines_1[i][1]);
Point2i pt2_1(lines_1[i][2], lines_1[i][3]);
//cout << lines[i][0] << " " << lines[i][1] << " " << lines[i][2] << " " << lines[i][3] << endl;
dis_1.push_back(sqrt(abs((pt1_1.x - pt2_1.x)) * abs((pt1_1.x - pt2_1.x)) + abs((pt1_1.y - pt2_1.y)) * abs((pt1_1.y - pt2_1.y))));
line(result, pt1_1, pt2_1, Scalar(0, 0, 255), 1, LINE_AA);
}
for (int i = 0; i < dis.size(); i++) {
cout << "dis = " << dis[i] << endl;
}
for (int i = 0; i < dis_1.size(); i++) {
cout << "dis_1 = " << dis_1[i]/1.2 << endl;
}
imshow("src", srcImg);
imshow("0.6, 1.2", resultImg);
imshow("src", src);
imshow("result", result);
waitKey(0);
return 0;
}
Mat LinerInter(Mat &srcImage, double kx, double ky)
{
int rows = cvRound(srcImage.rows*kx);
int cols = cvRound(srcImage.cols*ky);
Mat resultImg(rows, cols, srcImage.type());
int i, j;
int xi;
int yi;
int x11;
int y11;
double xm;
double ym;
double dx;
double dy;
for (i = 0; i < rows; i++)
{
xm = i / kx;
xi = (int)xm;
x11 = xi + 1;
dx = xm - xi;
for (j = 0; j < cols; j++)
{
ym = j / ky;
yi = (int)ym;
y11 = yi + 1;
dy = ym - yi;
//判断边界
if (x11 >(srcImage.rows - 1))
{
x11 = xi - 1;
}
if (y11 > (srcImage.cols - 1))
{
y11 = yi - 1;
}
//bgr
resultImg.at<Vec3b>(i, j)[0] = (int)(srcImage.at<Vec3b>(xi, yi)[0] * (1 - dx)*(1 - dy)
+ srcImage.at<Vec3b>(x11, yi)[0] * dx*(1 - dy)
+ srcImage.at<Vec3b>(xi, y11)[0] * (1 - dx)*dy
+ srcImage.at<Vec3b>(x11, y11)[0] * dx*dy);
resultImg.at<Vec3b>(i, j)[1] = (int)(srcImage.at<Vec3b>(xi, yi)[1] * (1 - dx)*(1 - dy)
+ srcImage.at<Vec3b>(x11, yi)[1] * dx*(1 - dy)
+ srcImage.at<Vec3b>(xi, y11)[1] * (1 - dx)*dy
+ srcImage.at<Vec3b>(x11, y11)[1] * dx*dy);
resultImg.at<Vec3b>(i, j)[2] = (int)(srcImage.at<Vec3b>(xi, yi)[2] * (1 - dx)*(1 - dy)
+ srcImage.at<Vec3b>(x11, yi)[2] * dx*(1 - dy)
+ srcImage.at<Vec3b>(xi, y11)[2] * (1 - dx)*dy
+ srcImage.at<Vec3b>(x11, y11)[2] * dx*dy);
}
}
return resultImg;
}
结果:
不知道这个思路对不对,恳请斧正!
近邻插值:
# include<iostream>
# include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
Mat NearInter(Mat &srcImage, double kx, double ky)
{
int rows = cvRound(srcImage.rows*kx);
int cols = cvRound(srcImage.cols*ky);
Mat resultImg(rows, cols, srcImage.type());
int i, j, x, y;
for (i = 0; i < rows; i++)
{
x = static_cast<int>((i + 1) / kx + 0.5) - 1;
for (j = 0; j < cols; j++)
{
y = static_cast<int>((j + 1) / ky + 0.5) - 1;
resultImg.at<Vec3b>(i, j) = srcImage.at<Vec3b>(x, y);
}
}
return resultImg;
}
int main()
{
Mat srcImg = imread("D:\\Visual Studio 2015\\lena.bmp");
Mat resultImg = NearInter(srcImg, 0.6, 1.2);
imshow("src", srcImg);
imshow("0.6,1.2", resultImg);
waitKey(0);
return 0;
}
————————————————
原文链接:https://blog.csdn.net/xuan_zizizi/article/details/82747729
三次插值:
# include<iostream>
# include<cmath>
# include<opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
float Bicubic(float x);
Mat ThreeInter(Mat &srcImage, double kx, double ky);
int main()
{
Mat srcImg = imread("D:\\Visual Studio 2015\\lena.bmp");
if (!srcImg.data)
{
cout << "图片不存在" << endl;
}
Mat resultImg = ThreeInter(srcImg, 0.6, 1.2);
imshow("src", srcImg);
imshow("0.6,1.2", resultImg);
waitKey(0);
return 0;
}
float Bicubic(float y)
{
float x = abs(y);
float a = -0.5;
if (x <= 1.0)
{
return (a + 2)*pow(x, 3) - (a + 3)*pow(x, 2) + 1;
}
else if (x < 2.0)
{
return a*pow(x, 3) + 5 * a*pow(x, 2) - 4 * a;
}
else
{
return 0.0;
}
}
Mat ThreeInter(Mat &srcImage, double kx, double ky)
{
int rows = cvRound(srcImage.rows * kx);
int cols = cvRound(srcImage.cols * ky);
Mat resultImg(rows, cols, srcImage.type());
int i, j;
int xm, ym;
int x0, y0, xi, yi, x1, y1, x2, y2;
float wx0, wy0, wxi, wyi, wx1, wy1, wx2, wy2;
float w00, w01, w02, w0i, w10, w11, w12, w1i, w20, w21, w22, w2i, wi0, wi1, wi2, wii;
for (i = 0; i < rows; i++)
{
xm = i / kx;
xi = (int)xm;
x0 = xi - 1;
x1 = xi + 1;
x2 = xi + 2;
wx0 = Bicubic(x0 - xm);
wxi = Bicubic(xi - xm);
wx1 = Bicubic(x1 - xm);
wx2 = Bicubic(x2 - xm);
for (j = 0; j < cols; j++)
{
ym = j / ky;
yi = (int)ym;
y0 = yi - 1;
y1 = yi + 1;
y2 = yi + 2;
wy0 = Bicubic(y0 - ym);
wyi = Bicubic(yi - ym);
wy1 = Bicubic(y1 - ym);
wy2 = Bicubic(y2 - ym);
w00 = wx0*wy0;
w01 = wx0*wy1;
w02 = wx0*wy2;
w0i = wx0*wyi;
w10 = wx1*wy0;
w11 = wx1*wy1;
w12 = wx1*wy2;
w1i = wx1*wyi;
w20 = wx2*wy0;
w21 = wx2*wy1;
w22 = wx2*wy2;
w2i = wx2*wyi;
wi0 = wxi*wy0;
wi1 = wxi*wy1;
wi2 = wxi*wy2;
wii = wxi*wyi;
if ((x0 >= 0) && (x2 < srcImage.rows) && (y0 >= 0) && (y2 < srcImage.cols))
{
resultImg.at<Vec3b>(i, j) = (srcImage.at<Vec3b>(x0, y0)*w00 + srcImage.at<Vec3b>(x0, y1)*w01 + srcImage.at<Vec3b>(x0, y2)*w02 + srcImage.at<Vec3b>(x0, yi)*w0i
+ srcImage.at<Vec3b>(x1, y0)*w10 + srcImage.at<Vec3b>(x1, y1)*w11 + srcImage.at<Vec3b>(x1, y2)*w12 + srcImage.at<Vec3b>(x1, yi)*w1i
+ srcImage.at<Vec3b>(x2, y0)*w20 + srcImage.at<Vec3b>(x2, y1)*w21 + srcImage.at<Vec3b>(x2, y2)*w22 + srcImage.at<Vec3b>(x2, yi)*w2i
+ srcImage.at<Vec3b>(xi, y0)*wi0 + srcImage.at<Vec3b>(xi, y1)*wi1 + srcImage.at<Vec3b>(xi, y2)*wi2 + srcImage.at<Vec3b>(xi, yi)*wii);
}
}
}
return resultImg;
}
————————————————
原文链接:https://blog.csdn.net/xuan_zizizi/article/details/82747729
下一篇: Java利用IO流输出文件
推荐阅读