c++图像处理
不定期更新
第一例 图像扭曲的C++实现
前言
本内容针对图像做水平、垂向扭曲,实现算法包括线性插值、卷积,注意的问题不卷积的边界处理及边缘锯齿。
一、基于线性插值的图像扭曲
直接上代码
下面展示一些 内联代码片
。
// 水平扭曲
//Mat 为openvc图像结构,所以需要加入openvc库
using namespace cv;
Mat HoriSkew3(Mat image, double delt) {
//Mat dst(image);
int row = image.rows;
int col = image.cols;
int rownew = image.rows;
int colnew = delt>=0?(int)ceil(col + row * delt): (int)ceil(col - row * delt);
Mat dst = Mat::zeros(rownew, colnew, CV_32FC3);
if (delt >= 0) {
for (int h = 0; h < row; ++h)
{
for (int w = (int)floor(h * delt); w < (int)ceil(col + h * delt); ++w)
{
int lowcol = w - (int)floor(h * delt);
int upcol = w - (int)floor(h * delt) + 1;
if (upcol >= col) continue;
Vec3b a = image.at<Vec3b>(h, lowcol);
Vec3f* ptr = dst.ptr<Vec3f>(h, w); //dst.at<Vec3b>(h, w)[0] = 0;
ptr->val[0] = image.at<Vec3b>(h, lowcol).val[0] + (h * delt - (int)floor(h * delt)) *
(image.at<Vec3b>(h, upcol).val[0] - (float)image.at<Vec3b>(h, lowcol).val[0]);
ptr->val[1] = image.at<Vec3b>(h, lowcol).val[1] + (h * delt - (int)floor(h * delt)) *
(image.at<Vec3b>(h, upcol).val[1] - (float)image.at<Vec3b>(h, lowcol).val[1]);
ptr->val[2] = image.at<Vec3b>(h, lowcol).val[2] + (h * delt - (int)floor(h * delt)) *
(image.at<Vec3b>(h, upcol).val[2] - (float)image.at<Vec3b>(h, lowcol).val[2]);
}
}
}
else {
delt = abs(delt);
flip(image, image, 1);
//复制上面代码就可以了
/****
水平扭曲代码
****/
flip(dst, dst, 1);
}
return dst;
}
这一部分比较简单,略过
二、使用卷积算法实现水平扭曲
1.原理
扭曲最大的问题在于:扭曲后的点不位于像素采样点上,所以解决办法为先移动最小整数点、再移动分数阶点(采用总卷积实现)。
分数阶移动原理:
h
(
x
)
=
∑
x
=
0
n
s
i
n
c
(
n
−
x
)
=
s
i
n
(
(
n
−
x
)
∗
Π
)
/
(
n
−
x
)
/
Π
h(x)= \displaystyle \sum_ {x=0}^{n}sinc(n-x)=sin((n-x)*\Pi)/(n-x)/\Pi
h(x)=x=0∑nsinc(n−x)=sin((n−x)∗Π)/(n−x)/Π
其中
x
x
x为分数阶,值可以是
(
0
,
1
)
(0,1)
(0,1),或者是$(-0.5,0.5),具体看如何取整数点。
代码如下(示例):
Mat HorSkewBySinc3(Mat image, double delt,int halfwind) {
int row = image.rows;
int col = image.cols;
int rownew = image.rows;
int colnew = delt >= 0 ? (int)ceil(col + row * delt) : (int)ceil(col - row * delt);
Mat dst = Mat::zeros(rownew, colnew, CV_32FC3);
//int wholeshift = (int)floor(row * delt);
if (delt >= 0) {
for (int h = 0; h < rownew; h++)
{
int wholeshift = (int)floor(h * delt);
//整体移动
for (int w = wholeshift; w < col + wholeshift; w++)
{
Vec3f* ptr = dst.ptr<Vec3f>(h, w);
ptr->val[0] = (double)image.at<Vec3b>(h, w - wholeshift).val[0];
ptr->val[1] = (double)image.at<Vec3b>(h, w - wholeshift).val[1];
ptr->val[2] = (double)image.at<Vec3b>(h, w - wholeshift).val[2];
}
//分数阶移动
vector<double> filter = sinc(halfwind, h * delt - wholeshift);//得到倒转后滤波参数
//vector<double> filter = sinc(halfwind, 0);
double total = 0;
int filLen = filter.size();
for (int i = - halfwind ; i < halfwind; i++) {
total += filter[i + filLen/2];//求整体增益量
}
Mat curRowData = dst.row(h).clone();
int curCol = col + wholeshift + 0;//当前列的行数
for (int i = wholeshift; i < curCol; i++) {
double sum1 = 0, sum2 = 0, sum3 = 0;
int index_boundary = 0;
//左扩边
if ((i - wholeshift) <= halfwind) {
//continue;
for (int j = -halfwind; j < halfwind; j++) {
Vec3f* ptr;
//Vec3f* ptr = dst.ptr<Vec3f>(i + j, w);
if (i + j < wholeshift)
ptr = curRowData.ptr<Vec3f>(0, 2*wholeshift -(i+j));
else ptr = curRowData.ptr<Vec3f>(0, i + j);
sum1 += ptr->val[0] * filter[j + filLen / 2] / total;
sum2 += ptr->val[1] * filter[j + filLen / 2] / total;
sum3 += ptr->val[2] * filter[j + filLen / 2] / total;
}
}
else if ( i > (curCol - halfwind)) {
//continue;
//index_boundary = i;
//右扩边
//continue;
for (int j = -halfwind; j < halfwind; j++) {
Vec3f* ptr;
//Vec3f* ptr = dst.ptr<Vec3f>(i + j, w);
if (i + j >= curCol)
ptr = curRowData.ptr<Vec3f>(0, (curCol - 1 - ((i + j) - (curCol-1))));
else ptr = curRowData.ptr<Vec3f>(0,i + j);
sum1 += ptr->val[0] * filter[j + filLen/2 ] / total;
sum2 += ptr->val[1] * filter[j + filLen/2 ] / total;
sum3 += ptr->val[2] * filter[j + filLen/2 ] / total;
}
}
//中间部分
else if((i - wholeshift) > halfwind && i <= (curCol - halfwind)) {
//continue;
index_boundary = curCol - filter.size();
for (int j = -halfwind; j < halfwind; j++) {
Vec3f* ptr = curRowData.ptr<Vec3f>(0,i + j);
sum1 += ptr->val[0] * filter[j + filLen/2] / total;
sum2 += ptr->val[1] * filter[j + filLen/2 ] / total;
sum3 += ptr->val[2] * filter[j + filLen/2 ] / total;
}
}
//cout << dst.ptr<Vec3f>(h, i)->val[0] << " ";
dst.ptr<Vec3f>(h,i)->val[0] = sum1;
dst.ptr<Vec3f>(h,i)->val[1] = sum2;
dst.ptr<Vec3f>(h,i)->val[2] = sum3;
//cout << curRowData.ptr<Vec3f>(0, i)->val[0] << " ";
//cout << sum1 << " " << sum2 << " " << sum3 << " ";
}
curRowData.release();
//右边缘柔化
if (h + 1 > row-2)continue;
dst.ptr<Vec3f>(h, curCol)->val[0] = dst.ptr<Vec3f>(h, curCol-1)->val[0] /3*2 +dst.ptr<Vec3f>(h+1, curCol - 1)->val[0]/3*0;
dst.ptr<Vec3f>(h, curCol )->val[1] = dst.ptr<Vec3f>(h, curCol - 1)->val[1] / 3 * 2 + dst.ptr<Vec3f>(h + 1, curCol - 1)->val[1] * 0 / 3;
dst.ptr<Vec3f>(h, curCol )->val[2] = dst.ptr<Vec3f>(h, curCol - 1)->val[2] / 3 * 2 + dst.ptr<Vec3f>(h + 1, curCol - 1)->val[2] * 0 / 3;
dst.ptr<Vec3f>(h, curCol + 1)->val[0] = dst.ptr<Vec3f>(h, curCol)->val[0] / 2;
dst.ptr<Vec3f>(h, curCol + 1)->val[1] = dst.ptr<Vec3f>(h, curCol)->val[1] / 2;
dst.ptr<Vec3f>(h, curCol + 1)->val[2] = dst.ptr<Vec3f>(h, curCol)->val[2] / 2;
dst.ptr<Vec3f>(h, curCol - 1)->val[0] = dst.ptr<Vec3f>(h, curCol-2)->val[0] / 3 *2 + dst.ptr<Vec3f>(h, curCol)->val[0] / 3;
dst.ptr<Vec3f>(h, curCol - 1)->val[1] = dst.ptr<Vec3f>(h, curCol - 2)->val[1] / 3*2 + dst.ptr<Vec3f>(h , curCol)->val[1] / 3;
dst.ptr<Vec3f>(h, curCol - 1)->val[2] = dst.ptr<Vec3f>(h, curCol - 2)->val[2] / 3*2 + dst.ptr<Vec3f>(h , curCol)->val[2] / 3;
//左边缘柔化
if (wholeshift <= 1)continue;
dst.ptr<Vec3f>(h, wholeshift-1)->val[0] = dst.ptr<Vec3f>(h, wholeshift )->val[0] / 3 * 2 + dst.ptr<Vec3f>(h + 1, wholeshift -1)->val[0] / 3 * 0;
dst.ptr<Vec3f>(h, wholeshift-1)->val[1] = dst.ptr<Vec3f>(h, wholeshift )->val[1] / 3 * 2 + dst.ptr<Vec3f>(h + 1, wholeshift - 1)->val[1] * 0 / 3;
dst.ptr<Vec3f>(h, wholeshift-1)->val[2] = dst.ptr<Vec3f>(h, wholeshift )->val[2] / 3 * 2 + dst.ptr<Vec3f>(h + 1, wholeshift - 1)->val[2] * 0 / 3;
dst.ptr<Vec3f>(h, wholeshift - 2)->val[0] = dst.ptr<Vec3f>(h, wholeshift-1)->val[0] / 2;
dst.ptr<Vec3f>(h, wholeshift - 2)->val[1] = dst.ptr<Vec3f>(h, wholeshift-1)->val[1] / 2;
dst.ptr<Vec3f>(h, wholeshift - 2)->val[2] = dst.ptr<Vec3f>(h, wholeshift-1)->val[2] / 2;
dst.ptr<Vec3f>(h, wholeshift )->val[0] = dst.ptr<Vec3f>(h, wholeshift-1)->val[0] / 3 * 2 + dst.ptr<Vec3f>(h, wholeshift+1)->val[0] / 3;
dst.ptr<Vec3f>(h, wholeshift )->val[1] = dst.ptr<Vec3f>(h, wholeshift-1)->val[1] / 3 * 2 + dst.ptr<Vec3f>(h, wholeshift + 1)->val[1] / 3;
dst.ptr<Vec3f>(h, wholeshift )->val[2] = dst.ptr<Vec3f>(h, wholeshift-1)->val[2] / 3 * 2 + dst.ptr<Vec3f>(h, wholeshift + 1)->val[2] / 3;
}
}
else {
delt = abs(delt);
flip(image, image, 1);
/******
这里复制上面的代码即可
*******/
flip(dst, dst, 1);
}
return dst;
}
总结
提示:这里对文章进行总结:
本文给出的方法提供一个思路,代码还有很大优化空间,有问题可以咨询我,邮件:sunger7@163.com