python如何对两个矩阵进行拼接_一起学opencv-python三十五(特征匹配之求取变换矩阵和图像拼接融合)...

708d5ac4226b71a19ee5005feb0074eb7643605a.png

官方例子给的是用掩模来过滤点的代码,其实效果是一样的,这个调用不需要加_create。23647f8fb2331d4bf5856401df3d8c050cbf2b65.png

掩模的话,就是只有对应位置非0,才会把连线画出来的,上面不知道你们是否还记得**的用法。fdb79cf57410bd8a41950c528a1d27d998ef2dcf.png

这个输入只能是两个参数,这两个参数应该规定就是字典了,下面这样其实也是可以的。

我稍微比较了一下时间:77743752ab9d445bef63181f7c0cfde6d6624d07.png

f6299ee5e1350bf6815899dd3fcfd914df00a523.png

enmmm,FLANN并不是时间更短啊。

还有一点需要注意的是:aa1a509407d8316f31b23982285da040fc82d4b1.png

8dde83574fd50e7a3c4174adec9eb10f5b5ce69b.png

前两个不是用二进制描述的,没有问题,这里用二进制描述的就不行了。61c8232253db39d46273e27e3d380c7b7971a51b.png

显示的是不支持这种格式的。88cdb2659d3966ab7f5b2bc9cfdda48f3d709851.png

BRISK的也不行。说明FLANN_INDEX_KDTREE算法不能用二进制的描述。7af912b4f4e5a587592a03294f18b91f568d0f74.png

用了opencv官方给的ORB的例子也出错。我的opencv版本这里再说一下:cfaad88f1d44f6825d38943e6e3c8cdaf8fee08e.png

不过opencv已经出了4,肯定时会有一定的变化的。不过其实问题在于数据格式,在网上查了资料http://answers.opencv.org/question/59996/flann-error-in-opencv-3/

说是flann的输入需要时浮点类型的32F。531135a1c49f2adff01a7ec9286656219dd0f9e5.png

我这里查到了汉明2距离的计算,它就是把两个比特位相加,然后按照一个比特位对待,然后按照汉明距离计算。5974155520d874d37e90d7ee153c159e3d3a6cf2.png

不过不能按照汉明距离去计算。aed9b9cbe6b4001df91c6a8bbdefda87c4615327.png

这里我们只是利用了normalize函数来把整数化为32F,不过这样其实有问题,因为原来的二进制应该按照汉明距离来匹配,但是现在却是按照欧式距离。我们看一下结果:7805b299f116e8a8ac897d2f1295a4fd3b6cfab1.png

有几个还不错,但是蓝线时明显不对的。现在还不太知道FLANN怎么按照汉明距离来分类。这个其实用np.float32也可以实现:392a59b4d8b0d3d104865d6fcd615e3ab8b851b1.png

我们上面做的事情是在一张图片上找到特征点,我们找另一张图片,也找到特征点,然后匹配这些特征点。简单地说,我们在图中找到了一个物体某些部分的位置。这个信息足以在第二张图片中找到这个物体(也就是说我们在第二张图片中找到第一张图片中的指定物体)。这个我们前面尝试过,用模板匹配和直方图匹配都试过,但是,它们的尺度和旋转不变性很差,以前我们介绍过七种矩,它们的值可以用来作为识别物体的工具,现在我们用的是特征点匹配。有的时候,比如图像配准,我们需要知道两张图像的透视变换关系(之所以说是透视变换是因为它可以包含仿射变换)。我们是用calib3d模块里面的cv2.findHomography函数。如果我们把两幅图对应的点集作为参数传进去。它会找到这个透视变换关系,也就是透视变换矩阵M。关于透视变换,可以看一看:2fdce60506cd82d0681c7a14e915e0cb57c9107f.png

7bced520e719e09cf7d4afbe31ef5e3d171e2cda.png

找到了透视变换关系之后可以用cv2.perspectiveTransform来实现这个变换,我们知道在匹配的时候会出现错误,这会影响最后的结果。为了解决这个问题,使用RANSAC或者LEAST_MEDIAN算法来解决。所以好的匹配给出的是好的结果,被叫做样本点,其它的不太好的结果叫做极端点。cv2.findHomography会返回一个掩模,这个掩模可以区分样本点和极端点。我们先来研究一下这两个函数:65a068eae5de8de4f3e8c43ce713c6bbfe599a6f.png

首先注意输入的类型应该是32F。第三个参数比较重要,是方法,0用的是用所有点的最小二乘法,这个大家都学过,其实这个找关系的步骤就像是一个拟合的过程,其实就是确定透视矩阵M的8个参数,但是其实只需要4对点就可以确定8个参数,但是我们不止有4个点,我们可以确定很多组参数,怎么找到一组合适的参数呢?最小二乘给出了一种评价方法,就是让误差的平方和最小。RANSAC参考:https://www.cnblogs.com/weizc/p/5257496.html

和https://blog.csdn.net/zinnc/article/details/5231971659d75292e0fd10c047356af8eebd287868831883.png

104f994bd344a6080b5b69d9a251d72fb09023f3.png

80b33b0f1b7cdbd0ced3e1f459b85768cc6d1b2c.png

a80537ca58b39996669008faf2ccfd32529aba73.png

bc55e6ae77351d1dd4e00ee9155eef06cc8fb426.png

这种算法也很好理解,就是随机取四对点,计算出透视变换矩阵,再拿其它点经过这个透视变换,看看变换的结果和匹配点的距离有多远,如果这个距离太大,就舍弃这一组四个点,重复选点,直到满足一定条件,当然每次取的可以不是4对点,每次用最小二乘算出来一个透视变换关系。 Least-Median是最小二乘的改进,因为点里面会有很多噪声胡总和说无效点,计算误差平方和会被无效点或者说离群点带偏,因为为了让它们的偏差变小,整个拟合结果就被带偏了。而加权和或许是一个不错的方法,不过权重怎么给呢?这个权重可以根据最后的误差平方和来调整,不过这个比较麻烦。用误差平方的中值最小作为目标就会比较好,因为中值不容易被噪声带偏。参考https://blog.csdn.net/z63er9uc37lyne9v0m/article/details/8317958479bf50ee5bced09f2ba503ab730e1f362aa668cb.png

aa7537c7452a6885555a51c16494dea4d5d4a77d.png

参考https://blog.csdn.net/tianwaifeimao/article/details/485433619e5cb441cac04968042d0987f5c37dabdfc0d4c7.png

27d22e6ec5c42136e2535727503b58da39426519.png

44b5482b1f90961b8aa07fec99c0f76914c97586.png

fee0b3a9be3980ac9a218fb0cf5ab43f4244f7c3.png

b47d0e9239503d9d0dac7c1e3b88677da0f4a60b.png

这个说明的额比较详细:89fc9e2f484c50b9d5290cd1dd369c3a18285878.png

f8eb7d335292b273f9923b03e82b85ea0bb08384.png

0c71388c98a1851e683fe022034a4b596a3b93a1.png

746ec088199bddb14b0b9d1e808985560d0ffe57.png

14834af49065b44bcbae640e33e354a92a8394cb.png

98f4de5f79ff7d041ff27b9c968f6ae530fefaec.png

799bc2e35adeae45d8c624f646fc4b33831c0a3b.png

73e7d906eefda22344ec656a4259aff3c026cccd.png

第四个参数是阈值,也就是最大的允许的透视变换偏差,如果超过这个偏差,就不作为样本点(用在RANSAC和RHO方法里)。偏差用的是二范数,对于点来说就是欧式距离。mask是输出的矩阵,它标记了样本点和极端点(离群点)。maxiters是RANSAC的最大迭代次数,confidence是置信度,越大的话两个集合匹配的结果越好,但是剩下的点会很少。7e39ece8cff041134274d3c982c786fff2bde3c9.png

默认的方法是0,也就是最小二乘法,最后的结果可能找不出一个变换矩阵,这是返回的是空矩阵。原来我们用过:896a3d950c7bc22d341845f2e1cb83e7c204b860.png

这个函数的输入是四对点,结果是确定的,方程是封闭的。而上面用的可以输入多于4个点,用不同的方法可以得到不同的结果,因为方程比未知数多,就要用到一些拟合的方法。11f07e9f1207bd15312380740f7b2ec0264e5380.png

这个是实现变换的函数,输入可以是二维点,这个时候变换矩阵是3×3的,也可以是三维点,变换矩阵是4×4的。7371cefa83c4e78ee184765b8e33227e452440a9.png

这个是更直接一点,为什么里面会有插值呢?因为变换之后的结果不一定是整数,但是显示的时候一定是整数,那么就得用插值来得到整数点的值了。代码:842c8a025d88cf951357fc4a6a1c941e9807037e.png

这里设定了一个最小匹配点对数,如果获得的有效匹配点对数太少,不足以我们找到这个变换关系或者说变换关系不好。如果得到足够多的匹配点对,我们可以得到匹配点对在图像中的坐标,然后我们用它们来求出透视矩阵。19d4a9239aadc233053fc7ddb70100ad10399b9f.png

src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)

这一句首先float32是findHomography函数输入的要求,m.querydx是点的索引,再经过kp1就得到了坐标,最后的reshpe(-1,1,2)是为了符合格式:1cc10a543035e0fe508f37ae8c6482d2e0c959e9.png

这样也就是-1代表是不确定的值,不过应该是个整数。5fe8b449611fe3b4e6f1afd4d3d4c2bd9da1609c.png

看来findHomography的输出应该是样本点标记为1而离群点标记为0了。10aa3b245b1c5d2246ca2b26e5ee63547af0c46d.png

bb3fdda0460eb5165f3a496b5e85f6273af27989.png

9aee95038795b28ad73f5f7cb8649a1a94d7ef66.png

图2中红色边框是图一经过映射之后的边界。

换一种方法,用LMEDS:1819dd6bcd5bc6efa80f8b3883184430dab6f480.png

变换矩阵还是不太一样的呢。378e95f815222ef3fad0f9904c93da3cfb0da044.png

用变换矩阵变换图像之后。说明这个变换矩阵还是很好的。

opencv图像拼接和融合

这个和利用金字塔融合是不一样的,那个是强行融合,这个是找到相对应的特征点,然后根据特征点匹配的结果来拼接和融合。参考了https://www.cnblogs.com/skyfsm/p/7411961.html和http://blog.sina.com.cn/s/blog_cfc0eb8f0101k8vz.htmlc619529ed53c42d131ac30a469e16db0e79de78d.png

fce88152278fb4a4ba97d580694b34ad6dd00d0b.png

我们这里就用SIFT来提取特征点,接着上面的工作继续做下去。其实上面我们已经做了不少工作了,下一步就是要把两幅图拼接在一起了。b54559e6035143faf8774ca6f3d0c925c99e0b9a.jpgt1.png

0442062001441bd8ce63b62ca39be805ca7b046e.jpgt2.png

我拿这两幅图作为测试。如果要拼接三张,其实就是两次两两拼接,所以掌握了两两拼接就够了。252ed7cd58909b72bc47ab1b6579a6bd8b905fb8.png

这个变换的时候最好是从右边的图片变到左边而不是左边到右边,因为左边到右边的话,经过透视变换之后,左边图片的左边部分丢失了,反过来就不会有问题了。d58e287a5f5b29cd2f7b482a00499757d4d2021b.png

然后就可以直接拼接了,但是拼接后的大小要事先计算一下。e5db4db873d84ef3922c9663abdb29b007d13900.png

先计算右边图像2变换之后在左边图像中的最左边界位置,看到是510.6725。然后再计算右边图像经过透视变换之后需要多宽。ab04822dc19498fcb7a6dd1b90f5a1baec274472.png

最右减去最左,然后就可以确定拼接之后的宽度为b1+d了。e39667c6af1975dda2cd94259167d2ea01aa0a08.png

这个错误是因为少了一个int。e115e106a8daaa5655e4e91c14278080971174b8.png

结果:3ed73285f3d1e18444ac4f99aac938466f2449a1.png

中间重叠的部分由于加了两次,所以就会过分的亮,这个好解决。02db899532b9bd091b533492f791e3fdbed8ad9b.png

拼接结果:e4099b0851ce3b6fa7abb0dc60f419aa4e241bd7.png

中间有些过渡的地方还是有些突兀的。这个时侯最好的办法不是滤波,也不是金字塔融合,因为它们都会让原图模糊,最好的办法是加权融合,这样会让边界不那么明显。5a2af60cbb653fbb314ece5ce9fb4cfa85a9f07a.png

这个加权得自己写程序,我写的意思是黑色的不参与加权,只有那些不是黑色的地方参与加权,权重各为0.5,效果:cb060f7a6e715e937e75c7568257e7d80cc3fd7f.png

过渡是自然了,但是那条裂缝很明显,我感觉很奇怪为什么会有裂缝,并且右边有一些黑色区域,这个我们可以这样处理。因为裂缝那个区域是两张图片一起加的,img1那里不是0,加起来怎么会得到结果是0呢。a9b4defe44a863d490d90ed1a1da3031d9366cd6.png

我把透视变换那一步的插值方式换了一下,而且宽度也变了,不是用dst的最右边点了,而是用次右边。

结果:97f823221d9b376a6fed510615a1bc8b5290d3a6.png

裂缝相比上面没那么明显,但是还是看得到,但是这种插值方式出来的结果是最好的了。那个地方看起来明显是因为左右的亮度差太明显。1b374727afbecbde221db3f5b573c39c316ef894.png

如果调整一下权重。看起来还是有点奇怪。4b71f817ccc686f4271267a6c45bb4cfee4e2c32.png

我最后想到一种比较好的办法。e1ac37199e067ee2709926008e5d0092a3c2c236.png

我们只在最后的重合的10列里进行加权,效果:46b9de3873aa755e22652f9698661525bc4b45d6.png

觉得效果不好的话,你可以再增加列数。

Stitcher

这个类就是用来拼接图像的:d72b582fad7769b04c35e8ae05f21338eb442896.png

参考了https://stackoverflow.com/questions/34362922/how-to-use-opencv-stitcher-class-with-python474d3c7e40cacbc8282351c951207e73cbb11b31.png

63444108c354127f289d538ac92d9a4626af8fc2.png

裁剪一下就可以了,虽然这个原理不是很清楚呢,因为不要想去看源码。

三张也可以:278915a874163c0b035d6a480b743c7cc7566200.png

如果是不沾边的图像输进去呢?a1addd87b1cd190bfecfa64d8e323d307430884e.png

至少有两张可以拼接的,ret返回就是0,没有就是1。6b9b455873eb3076f336f20b8e1835c072d376d3.png

74d70cf3755853db4b876d20362fa944d8fd6ff2.png2.png

2084d471491e263edb693fcd8433482506ea183f.jpgt3.png

d1588e08396948d01d8c3cc53a742748e8bace42.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值