c++图像处理 skew算法

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=0nsinc(nx)=sin((nx)Π)/(nx)/Π
其中 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值