深圳市网站哪家做的好,山西两学一做网站,做违法网站会怎样,分类网站模板这里写自定义目录标题 图像匹配图像匹配代码 图像融合main.py运行代码 总的来说#xff0c;步骤如下#xff1a; 效果如下#xff1a; 拼接好的图如下#xff1a;
图像匹配
依次为 特征点提取#xff0c;特征点筛选#xff0c;图像变换。 常见的图像匹配算法有… 这里写自定义目录标题 图像匹配图像匹配代码 图像融合main.py运行代码 总的来说步骤如下 效果如下 拼接好的图如下
图像匹配
依次为 特征点提取特征点筛选图像变换。 常见的图像匹配算法有
图像匹配代码
基于opencv的sift以及SuperNet的特征点提取、特征点筛选的图像变换注释部分为SuperNet特征点提取。 文件目录
保存在matchers.py
import cv2
import numpy as np
import time
import matplotlib.pyplot as plt
import torch# traditional sift using opencv API
class SIFTMatcher():def __init__(self):#### get keypionts# Initiate SIFT detectorself.sift cv2.SIFT_create() # self.sift cv2.xfeatures2d_SIFT().create() # for older version of opencv # find the keypoints and descriptors with SIFTFLANN_INDEX_KDTREE 1index_params dict(algorithm FLANN_INDEX_KDTREE, trees 5)search_params dict(checks 50)self.flann cv2.FlannBasedMatcher(index_params, search_params)def match(self,dstImg,srcImg,direction,overlap0.5,scale4): # add overlap# # RETURN M TO transfer srcImg onto dstImg# print(Direction : , direction)imgDstGray cv2.cvtColor(dstImg, cv2.COLOR_BGR2GRAY)imgSrcGray cv2.cvtColor(srcImg, cv2.COLOR_BGR2GRAY)# crop iamge to calculate feature matching to boostsrcOffset int(overlap*imgSrcGray.shape[1])# print(SrcOFFSET :,srcOffset)imgSrcCrop imgSrcGray[:,:srcOffset] # oops all inverse# right Img/ Dst img default 1.2 size of leftdstOffset max(0,int(imgDstGray.shape[1]-srcOffset*1.2)) # ori 1.2imgDstCrop imgDstGray[:,dstOffset:]# resize image before matching to accelerate# scale scaleresized_imgDstCrop cv2.resize(imgDstCrop,(int(imgDstCrop.shape[1]/scale),int((imgDstCrop.shape[0]/scale))),interpolationcv2.INTER_AREA)resized_imgSrcCrop cv2.resize(imgSrcCrop,(int(imgSrcCrop.shape[1]/scale),int((imgSrcCrop.shape[0]/scale))),interpolationcv2.INTER_AREA)# find the keypoints and descriptors with SIFT# kp1, des1 self.sift.detectAndCompute(imgDstCrop, None) # dst# kp2, des2 self.sift.detectAndCompute(imgSrcCrop, None)kp1, des1 self.sift.detectAndCompute(resized_imgDstCrop, None) # dstkp2, des2 self.sift.detectAndCompute(resized_imgSrcCrop, None)# cv2.imwrite(results/str(imgSrcCrop[0][100])imgSrcCrop.jpg,imgSrcCrop)# print(imgSrcCrop.shape,imgDstCrop.shape)# cv2.imwrite(results/tmp/str(time.time())resized_SrcCrop.jpg,resized_imgSrcCrop)# cv2.imwrite(results/tmp/str(time.time())resized_DstCrop.jpg,resized_imgDstCrop)matches self.flann.knnMatch(des1, des2, k2)# # Need to draw only good matches, so create a mask# matchesMask [[0, 0] for i in range(len(matches))]good []pts1 []pts2 []# ratio test as per Lowes paperfor i, (m, n) in enumerate(matches):if m.distance 0.9 * n.distance: # default 0.7good.append(m)rows, cols dstImg.shape[:2]MIN_MATCH_COUNT 10if len(good) MIN_MATCH_COUNT:print(fGOOD匹配点数量为{len(good)})dst_pts np.float32([kp1[m.queryIdx].pt for m in good])#.reshape(-1, 1, 2) # dstsrc_pts np.float32([kp2[m.trainIdx].pt for m in good])#.reshape(-1, 1, 2)# print(src_pts, dst_pts)# scale backsrc_pts, dst_pts scale*src_pts, scale*dst_pts# xzdst_pts[:] [dstOffset,0]# print(after,src_pts)M, mask cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)# save matched picsmatchesMask mask.ravel().tolist()draw_params dict(matchColor (0,255,0),singlePointColor (255, 0, 0),matchesMask matchesMask, # draw only inliersflags 2)img4 cv2.drawMatches(dstImg,kp1,srcImg,kp2,good,None,**draw_params)# need mathces sub-folder under results foldercv2.imwrite(results/matches/str(time.time())matches_ransac.jpg,img4)# # plt.imshow(img4,), plt.show()# # print(M, M)return Melse:print(Not enough matches are found - {}/{}.format(len(good), MIN_MATCH_COUNT))matchesMask Nonereturn None# # Neural Networked based matching method
# # 2020 CVPR SuperGlue Net for matching# import sys
# sys.path.append(../SuperGluePretrainedNetwork-master/) # from models.matching import Matching
# from models.utils import frame2tensor# class SuperGlueMatcher():
# def __init__(self):
# self.device cuda if torch.cuda.is_available() else cpu
# self.config {
# superpoint: {
# nms_radius: 4,
# keypoint_threshold: 0.005,
# max_keypoints: -1
# },
# superglue: {
# weights: indoor,
# sinkhorn_iterations: 20,
# match_threshold: 0.25,
# }
# }
# self.model Matching(self.config).eval().to(self.device)# def match(self,dstImg,srcImg,direction,overlap0.5):# data {}
# data[image0] cv2.cvtColor(srcImg, cv2.COLOR_BGR2GRAY)
# data[image1] cv2.cvtColor(dstImg, cv2.COLOR_BGR2GRAY)# # size (800,600)
# # size image0.shape
# # data[image0] cv2.resize(imgSrcGray,size)
# # data[image1] cv2.resize(imgDstGray,size)# # crop iamge to calculate feature matching to boost
# srcOffset int(overlap*data[image0].shape[1])
# # print(SrcOFFSET :,srcOffset)
# data[image0] data[image0][:,:srcOffset] # oops all inverse
# # right Img/ Dst img default 1.2 size of left
# dstOffset max(0,int(data[image1].shape[1]-srcOffset*1.2))
# data[image1] data[image1][:,dstOffset:]# cv2.imwrite(results/tmp/str(time.time())SrcCrop.jpg,data[image0])
# cv2.imwrite(results/tmp/str(time.time())DstCrop.jpg,data[image1] )# # img to tensor
# imgToTensor0 frame2tensor(data[image0],self.device)
# last_data self.model.superpoint({image: imgToTensor0})
# keys [keypoints, scores, descriptors]
# last_data {k0: last_data[k] for k in keys}
# last_data[image0] imgToTensor0# imgToTensor1 frame2tensor(data[image1],self.device)# # pred2 matching({image0:imgToTensor0,image1:imgToTensor1})
# pred self.model({**last_data,image1:imgToTensor1})
# kpts0 last_data[keypoints0][0].cpu().numpy()
# kpts1 pred[keypoints1][0].cpu().numpy()
# matches pred[matches0][0].cpu().numpy() # 图一上的匹配点如果非匹配点则 -1# confidence pred[matching_scores0][0].cpu().detach().numpy() # it has grad
# # timer.update(forward)# valid matches -1
# mkpts0 kpts0[valid] # 图s0上的匹配点
# mkpts1 kpts1[matches[valid]] # 图s1上的匹配点# mkpts0, mkpts1 np.round(mkpts0).astype(int), np.round(mkpts1).astype(int)# mkpts1[:] [dstOffset,0]# if len(matches) 4:
# M, mask cv2.findHomography(mkpts0, mkpts1, cv2.RANSAC,5.0)
# else:
# M None
# print(fWarning! Only {len(matches)} searched!!!)
# return M
图像融合
保存在 blend.py文件中。
import numpy as npdef blend_linear(warp_img1, warp_img2):img1 warp_img1img2 warp_img2img1mask ((img1[:,:,0] | img1[:,:,1] | img1[:,:,2]) 0)img2mask ((img2[:,:,0] | img2[:,:,1] | img2[:,:,2]) 0)r,c np.nonzero(img1mask)out_1_center [np.mean(r),np.mean(c)]r,c np.nonzero(img2mask)out_2_center [np.mean(r),np.mean(c)]vec np.array(out_2_center) - np.array(out_1_center)intsct_mask img1mask img2mask# row col index of nonzero elementr,c np.nonzero(intsct_mask)out_wmask np.zeros(img2mask.shape[:2])# dot product of spherical coordinate and vec: measuring how much the vectors align or overlap in their directionsproj_val (r - out_1_center[0])*vec[0] (c- out_1_center[1])*vec[1]# min-max normalization of proj_val xzout_wmask[r,c] (proj_val - (min(proj_val)(1e-3))) / \((max(proj_val)-(1e-3)) - (min(proj_val)(1e-3)))# blendingmask1 img1mask (out_wmask0)mask2 out_wmaskmask3 img2mask (out_wmask0)out np.zeros(img1.shape)for c in range(3):out[:,:,c] img1[:,:,c]*(mask1(1-mask2)*(mask2!0)) \img2[:,:,c]*(mask2mask3)return np.uint8(out)def blend_max(img1,img2):# get max value for each pixelout np.zeros(img1.shape)mask img1 img2return np.uint8(img1*mask img2*(1-mask))# if __name____main__:
# import cv2
# img1 cv2.imread(warped_img1.jpg)
# img2 cv2.imread(warped_img2.jpg)
# out blend_linear(img1, img2)
# # cv2.imwrite(result.jpg,out)
main.py
import numpy as np
import cv2
import sys
from matchers import SIFTMatcher,SuperGlueMatcher
import time
import blendimport torch
torch.set_grad_enabled(False)class Stitch:def __init__(self, args):self.path argsfp open(self.path, r)filenames [each.rstrip(\r\n) for each in fp.readlines()] # remove tails# filenames argsprint(filenames)# self.images [cv2.resize(cv2.imread(each), (480, 320)) for each in filenames]self.images [cv2.imread(each) for each in filenames]self.count len(self.images)self.left_list, self.right_list, self.center_im [], [], Noneself.matcher_sift SIFTMatcher()self.matcher_nn SuperGlueMatcher()self.prepare_lists()def prepare_lists(self):Group images, suitable for single sequence, divide by left and rightprint(Number of images : %d % self.count)self.centerIdx self.count / 2# self.centerIdx self.count - 1print(Center index image : %d % self.centerIdx)self.center_im self.images[int(self.centerIdx)]for i in range(self.count):if (i self.centerIdx):self.left_list.append(self.images[i]) # not path, iamges in array else:self.right_list.append(self.images[i])print(Image lists prepared)def leftshift(self):# self.left_list reversed(self.left_list)a self.left_list[0]idx 0for b in self.left_list[1:]:start time.time()# return H : tranfer b onto asiftEnd time.time()H self.matcher_sift.match(a, b, left)# print(Time cost for sift matching this pair is {} s.format(siftEnd -start))# H_nn self.matcher_nn.match(a,b,left)# H H_nn# # print(H-H_nn)matchEnd time.time()print(Time cost for NN matching this pair is {} s.format(matchEnd -siftEnd))# print(Homography is : , H)xh np.linalg.inv(H) # so as to transfer a onto b, left to corner# print(Inverse Homography :, xh)br np.dot(xh, np.array([a.shape[1], a.shape[0], 1])) # bottom right point is (col, row) while shape is row,col xzbr br /br[-1] # to guarantee h33 is 1 xztl np.dot(xh, np.array([0, 0, 1])) # top lefttl tl / tl[-1]bl np.dot(xh, np.array([0, a.shape[0], 1])) # bottom leftbl bl / bl[-1]tr np.dot(xh, np.array([a.shape[1], 0, 1])) # top righttr tr / tr[-1]# Second item :original a, add b, cause b stands for rightImg, b usually has a larger border in left-right xzcx int(max([0, b.shape[1],tl[0], bl[0], tr[0], br[0]])) # a.shape[1],# only used for determinize size of new_srcImgcy int(max([0, b.shape[0],tl[1], bl[1], tr[1], br[1]])) # a.shape[0],offset [abs(int(min([0, a.shape[1], tl[0], bl[0], tr[0], br[0]]))), # to avoid negative coordinateabs(int(min([0, a.shape[0], tl[1], bl[1], tr[1], br[1]])))]dsize (cx offset[0], cy offset[1]) # iamge size for transformed iamge, large enoughprint(image dsize , dsize, offset, offset)tl[0:2] offset; bl[0:2] offset; tr[0:2] offset; br[0:2] offset # four tranformed corner pointsdstpoints np.array([tl, bl, tr, br])srcpoints np.array([[0, 0], [0, a.shape[0]], [a.shape[1], 0], [a.shape[1], a.shape[0]]])# print(sp,sp,dp,dp)M_off cv2.findHomography(srcpoints, dstpoints)[0] # Normally, transofrm first onto second zxz# print(M_off, M_off)warped_img2 cv2.warpPerspective(a, M_off, dsize)# cv2.imshow(warped, warped_img2)# cv2.waitKey()warped_img1 np.zeros([dsize[1], dsize[0], 3], np.uint8)# beacause of left to right, warped_img1[offset[1]:b.shape[0] offset[1], offset[0]:b.shape[1] offset[0]] b # offset for dstImag b also# tmp blend.blend_linear(warped_img1, warped_img2)tmp blend.blend_linear(warped_img1,warped_img2)a tmpstitchEnd time.time()print(Time cost for stitch is {} s.format(stitchEnd -matchEnd))cv2.imwrite(results/tmpLeft_str(idx).jpg,tmp)idx 1self.leftImage tmpdef rightshift(self):if len(self.right_list) 0: # if only two images, no need for rightshiftidx 0for each in self.right_list:start time.time()H self.matcher_sift.match(self.leftImage, each, right) # here, transform each onto leftImage# H_nn self.matcher_nn.match(self.leftImage, each, right)# H H_nnmatchEnd time.time()print(Time cost for matching this pair is {} s.format(matchEnd -start))# print(Homography :, H)br np.dot(H, np.array([each.shape[1], each.shape[0], 1]))br br / br[-1]tl np.dot(H, np.array([0, 0, 1]))tl tl / tl[-1]bl np.dot(H, np.array([0, each.shape[0], 1]))bl bl / bl[-1]tr np.dot(H, np.array([each.shape[1], 0, 1]))tr tr / tr[-1]cx int(max([0, each.shape[1], tl[0], bl[0], tr[0], br[0]])) #self.leftImage.shape[1], cy int(max([0, self.leftImage.shape[0],each.shape[0], tl[1], bl[1], tr[1], br[1]])) #self.leftImage.shape[0], offset [abs(int(min([0, each.shape[1], tl[0], bl[0], tr[0], br[0]]))),abs(int(min([0, each.shape[0], tl[1], bl[1], tr[1], br[1]])))]dsize (cx offset[0], cy offset[1])print(image dsize , dsize, offset, offset)tl[0:2] offset; bl[0:2] offset; tr[0:2] offset; br[0:2] offsetdstpoints np.array([tl, bl, tr, br]);srcpoints np.array([[0, 0], [0, each.shape[0]], [each.shape[1], 0], [each.shape[1], each.shape[0]]])M_off cv2.findHomography(dstpoints, srcpoints)[0]warped_img2 cv2.warpPerspective(each, M_off, dsize, flagscv2.WARP_INVERSE_MAP)# cv2.imshow(warped, warped_img2)# cv2.waitKey()warped_img1 np.zeros([dsize[1], dsize[0], 3], np.uint8)warped_img1[offset[1]:self.leftImage.shape[0] offset[1], offset[0]:self.leftImage.shape[1] offset[0]] self.leftImagetmp blend.blend_linear(warped_img1, warped_img2)self.leftImage tmpstitchEnd time.time()print(Time cost for stitch is {} s.format(stitchEnd -matchEnd))cv2.imwrite(results/tmpRight_str(idx).jpg,tmp)idx 1self.rightImage tmpdef showImage(self, stringNone):if string left:cv2.imshow(left image, self.leftImage)elif string right:cv2.imshow(right Image, self.rightImage)cv2.waitKey()if __name__ __main__:try:args sys.argv[1]except:args txtlists/keyboard.txtfinally:print(Parameters : , args)total_start time.time()s Stitch(args)# pipline for single sequences.leftshift()# cv2.imwrite(results/res_L.jpg, s.leftImage)s.rightshift()# # cv2.imwrite(results/res_R.jpg, s.leftImage)print(done)# ouput a file in the same name as input txtres args.split(/)[-1].split(.txt)[0] .jpgrotate Falseif rotate:s.leftImage cv2.rotate(s.leftImage,cv2.ROTATE_90_COUNTERCLOCKWISE)cv2.imwrite(results/ res, s.leftImage)print(result written)total_end time.time()print(Total time cost is {} s.format(total_end - total_start))# cv2.destroyAllWindows()
运行代码
python main.py 记录照片文件路径的文本路径文本内容举例如下
images/keyboard/keyboard01.jpeg
images/keyboard/keyboard02.jpeg
images/keyboard/keyboard03.jpeg
images/keyboard/keyboard04.jpeg