2021SC@SDUSC
前言
对于图片抗扭曲功能算法的实现,可以划分为以下任务:
1.采⽤寻找轮廓的⽅法,⽤approxPolyDP函数,对图像轮廓点进⾏多边形拟合
2.把图像的四个顶点处的点归类,划分出四个区域{左上,右上,右下,左下},利⽤opencv的寻找轮廓,得到最⼤轮廓,然后⽣成最⼩外接矩形,确定四个顶点的⼤致位置。设置⼀个阀值,与上图中的点集合求距离,⼤于阀值的舍弃,⼩于的保留。
3.所有的点集都落到了四个区域,利⽤矩形中,对⻆线距离最⼤,确定四个顶点的位置
4.根据输⼊和输出点获得图像透视变换的矩阵
5.透视变换。透视变换(Perspective Transformation)是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,仍能保持承影面上投影几何图形不变的变换。
这一篇我们将继续分析寻找轮廓方法的代码
一、项目环境
android studio版本 4.1.2
sdk版本 Compile SDK version:30
Build Tools Version 30.0.3
gradle版本 6.8.3
二、代码分析
1.透视变换,矫正图像
Mat dst = new Mat();
Imgproc.warpPerspective(src, dst, perspectiveMmat, src.size(), Imgproc.INTER_LINEAR + Imgproc.WARP_INVERSE_MAP,
1, new Scalar(0));
cv2.warpPerspective() 是透视变换函数,用于解决cv2.warpAffine()不能处理视场和图像不平行的问题。应用cv2.warpPerspective()前需先使用cv2.getPerspectiveTransform()得到转换矩阵。转换矩阵为3x3阶。这一个矩阵我们已经在之前得到了。
CV_EXPORTS_W void warpPerspective( InputArray src, OutputArray dst,
InputArray M, Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
函数参数解释如下:
src:输入图像
dst:输出图像,图像的类型须跟原图一致
M:转换矩阵
dsize :输出图像的大小
flags :表示插值方法的组合,线性插值或者最近邻插值;如设置了可选项WARP_INVERSE_MAP(变形插值映射),则会使得转换矩阵M为逆变形
borderMode :图像边界的处理方式
borderValue :边界的颜色设置,默认为0
Imgproc.warpPerspective(src, dst, perspectiveMmat, src.size(), Imgproc.INTER_LINEAR + Imgproc.WARP_INVERSE_MAP,
1, new Scalar(0));
则src是源图像,输出为经过透视变换后的图像dst,转换矩阵为perspectiveMmat,经由 Mat perspectiveMmat = Imgproc.getPerspectiveTransform(srcPoints, dstPoints)得到,输出图像的大小调整为和src的大小一样,插值方法的组合为变形插值映射和线性插值相结合,图像边界的处理方式选择了常数填充方法,颜色设置为默认0
String TAG = "CameraPreview";
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), TAG);//的搭配存储sd卡的位置
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());//时间戳,用来命名
Imgcodecs.imwrite(mediaStorageDir.getPath() + File.separator +
"IMG_" + timeStamp + ".jpg",dst);//文件命名
Uri uri = Uri
.parse(mediaStorageDir.getPath() + File.separator +
"IMG_" + timeStamp + ".jpg");//返回uri路径
至此,图片抗扭出算法已经处理完毕,新得到的已经完成变换后的图片存储在了相应位置,并且存储了uri路径
2.为按钮添加监听,完善功能
Button buttonok = (Button) findViewById(R.id.ok);
buttonok.setOnClickListener(new View.OnClickListener() {//添加监听事件
@Override
public void onClick(View v) {
Mat src;
String c = uri.getPath();
src= Imgcodecs.imread(uri.getPath());/载入图像
Uri uri1;
try {
uri1=warpPerspective(src);//得到透视变换后的图像
ImageView view = new ImageView(getApplicationContext());//得到承载img的view
view.setImageURI(uri1);//将view装入图像
preview.addView(view);//添加到预览view中
}catch (IndexOutOfBoundsException e){
Toast.makeText(getApplicationContext(),"矫正失败,请拍摄清晰一点的图片吧",Toast.LENGTH_LONG).show();
}
}
});
其中try——catch函数体是为了保证程序不会因为算法的偶然性而直接退出
至此,图片抗扭曲算法完成
效果展示:
矫正前:
矫正后:
三、总结
本次创新实训项目分析,我的任务是分析飞花令项目和图片抗扭曲算法两个项目,两个项目中我都学习到了很多。
飞花令项目相对简单一点,对于没有接触过as安卓开发的同学比较友好,可以很简单的就能上手页面之间传参的方式、消息传递以及view间的关系。
而图片抗扭曲算法相对难一点,里面用到了关于opencv的知识,需要进一步的去熟悉opencv的方法,并且在图片抗扭曲和透视转换上面,需要有更清晰的算法思路,开发人员的算法非常的清晰,步骤很完善,所以相对来说也是一个比较好上手的算法。从开始寻找最大轮廓、确定顶点的位置、得到透视转换的矩阵再到进行透视转换,所有过程串联起来得到了矫正过后的图像。
非常感谢这段时间对于这些代码的分析,让我对as有了入门的了解,也对as有了兴趣,相信在之后的手机开发方面,这一个学期的学习能为我建立起良好的基础