Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何检测图像之间的偏移_Python_Image_Image Processing_Scipy - Fatal编程技术网

Python 如何检测图像之间的偏移

Python 如何检测图像之间的偏移,python,image,image-processing,scipy,Python,Image,Image Processing,Scipy,我正在分析多个图像,需要能够判断它们是否与参考图像相比发生了偏移。其目的是判断相机在拍摄图像之间是否移动。理想情况下,我希望能够纠正偏移,以便仍能进行分析,但至少我需要能够确定图像是否发生偏移,并在超出某个阈值时丢弃它 下面是一些我想检测的图像中的偏移示例: 我将使用第一个图像作为参考,然后将下面的所有图像与之进行比较,以确定它们是否移位。这些图像是灰度的(它们只是使用热图以彩色显示),并存储在二维numpy阵列中。你知道我该怎么做吗?我更愿意使用我已经安装的软件包(scipy、numpy、P

我正在分析多个图像,需要能够判断它们是否与参考图像相比发生了偏移。其目的是判断相机在拍摄图像之间是否移动。理想情况下,我希望能够纠正偏移,以便仍能进行分析,但至少我需要能够确定图像是否发生偏移,并在超出某个阈值时丢弃它

下面是一些我想检测的图像中的偏移示例:


我将使用第一个图像作为参考,然后将下面的所有图像与之进行比较,以确定它们是否移位。这些图像是灰度的(它们只是使用热图以彩色显示),并存储在二维numpy阵列中。你知道我该怎么做吗?我更愿意使用我已经安装的软件包(scipy、numpy、PIL、matplotlib)。

作为
Lukas-Graf
提示,您正在寻找相互关联。如果:

  • 图像的比例变化不大
  • 图像中没有旋转变化
  • 图像中没有明显的照明变化
  • 对于普通翻译,互相关是非常好的

    最简单的互相关工具是
    scipy.signal.correlate
    。然而,它使用简单的互相关方法,对于边长为n的二维图像,互相关为O(n^4)。实际上,对于你的图像,这需要很长时间

    更好的也是
    scipy.signal.fftconvolve
    ,因为卷积和相关性密切相关

    大概是这样的:

    import numpy as np
    import scipy.signal
    
    def cross_image(im1, im2):
       # get rid of the color channels by performing a grayscale transform
       # the type cast into 'float' is to avoid overflows
       im1_gray = np.sum(im1.astype('float'), axis=2)
       im2_gray = np.sum(im2.astype('float'), axis=2)
    
       # get rid of the averages, otherwise the results are not good
       im1_gray -= np.mean(im1_gray)
       im2_gray -= np.mean(im2_gray)
    
       # calculate the correlation image; note the flipping of onw of the images
       return scipy.signal.fftconvolve(im1_gray, im2_gray[::-1,::-1], mode='same')
    
    im2_gray[::-1,::-1]
    的有趣索引将其旋转180°(水平和垂直镜像)。这是卷积和相关性之间的区别,相关性是第二个信号镜像后的卷积

    现在,如果我们只将第一个(最上面的)图像与其自身关联,我们得到:

    这给出了图像自相似性的度量。最亮的点在(201200)处,它位于(402400)图像的中心

    可以找到最亮的点坐标:

    np.unravel_index(np.argmax(corr_img), corr_img.shape)
    
    最亮像素的线性位置由
    argmax
    返回,但必须使用
    unravel_index
    将其转换回2D坐标

    接下来,我们通过将第一个图像与第二个图像关联来尝试相同的方法:

    相关性图像看起来类似,但最佳相关性已移至(149200),即图像中向上52个像素。这是两个图像之间的偏移量


    这似乎适用于这些简单的图像。然而,也可能存在虚假的相关峰,本答案开头列出的任何问题都可能破坏结果


    无论如何,你应该考虑使用窗口函数。功能的选择并不是那么重要,只要使用了某些东西。此外,如果您在小旋转或缩放更改方面遇到问题,请尝试将多个小区域与周围图像关联起来。这将在图像的不同位置提供不同的位移。

    另一种解决方法是计算两幅图像中的sift点,使用RANSAC去除异常值,然后使用最小二乘估计进行平移。

    正如Bharat所说,另一种方法是使用sift特征和RANSAC:

    import numpy as np
    import cv2
    from matplotlib import pyplot as plt
    
    def crop_region(path, c_p):
        """
          This function crop the match region in the input image
          c_p: corner points
        """    
        # 3 or 4 channel as the original
        img = cv2.imread(path, -1)
    
        # mask 
        mask = np.zeros(img.shape, dtype=np.uint8) 
    
        # fill the the match region 
        channel_count = img.shape[2]  
        ignore_mask_color = (255,)*channel_count
        cv2.fillPoly(mask, c_p, ignore_mask_color)
    
        # apply the mask
        matched_region = cv2.bitwise_and(img, mask)
    
        return matched_region
    
    def features_matching(path_temp,path_train):
        """
              Function for Feature Matching + Perspective Transformation
        """       
        img1 = cv2.imread(path_temp, 0)   # template
        img2 = cv2.imread(path_train, 0)   # input image
    
        min_match=10
    
        # SIFT detector
        sift = cv2.xfeatures2d.SIFT_create()
    
        # extract the keypoints and descriptors with SIFT
    
        kps1, des1 = sift.detectAndCompute(img1,None)
        kps2, des2 = sift.detectAndCompute(img2,None)
    
        FLANN_INDEX_KDTREE = 0
        index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
        search_params = dict(checks = 50)
    
        flann = cv2.FlannBasedMatcher(index_params, search_params)
    
        matches = flann.knnMatch(des1, des2, k=2)
    
        # store all the good matches (g_matches) as per Lowe's ratio 
        g_match = []
        for m,n in matches:
            if m.distance < 0.7 * n.distance:
                g_match.append(m)
        if len(g_match)>min_match:
            src_pts = np.float32([ kps1[m.queryIdx].pt for m in g_match ]).reshape(-1,1,2)
            dst_pts = np.float32([ kps2[m.trainIdx].pt for m in g_match ]).reshape(-1,1,2)
    
            M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0)
            matchesMask = mask.ravel().tolist()
    
            h,w = img1.shape
            pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
            dst = cv2.perspectiveTransform(pts,M)
    
            img2 = cv2.polylines(img2, [np.int32(dst)], True, (0,255,255) , 3, cv2.LINE_AA)
    
        else:
            print "Not enough matches have been found! - %d/%d" % (len(g_match), min_match)
            matchesMask = None
    
        draw_params = dict(matchColor = (0,255,255), 
                           singlePointColor = (0,255,0),
                           matchesMask = matchesMask, # only inliers
                           flags = 2)
        # region corners    
        cpoints=np.int32(dst)
        a, b,c = cpoints.shape
    
        # reshape to standard format
        c_p=cpoints.reshape((b,a,c))  
    
        # crop matching region
        matching_region = crop_region(path_train, c_p)
    
        img3 = cv2.drawMatches(img1, kps1, img2, kps2, g_match, None, **draw_params)
        return (img3,matching_region)
    
    将numpy导入为np
    进口cv2
    从matplotlib导入pyplot作为plt
    def裁剪区域(路径,c\p):
    """
    此函数用于裁剪输入图像中的匹配区域
    c_p:角点
    """    
    #3或4个通道作为原始通道
    img=cv2.imread(路径-1)
    #面具
    掩码=np.zero(img.shape,dtype=np.uint8)
    #填充匹配区域中的
    通道计数=图像形状[2]
    忽略遮罩颜色=(255,)*通道计数
    cv2.fillPoly(遮罩、c_p、忽略遮罩颜色)
    #戴上面具
    匹配的_区域=cv2。按位_和(img,掩码)
    返回匹配区域
    def功能匹配(路径温度、路径列车):
    """
    用于特征匹配+透视变换的函数
    """       
    img1=cv2.imread(路径温度,0)#模板
    img2=cv2.imread(路径列车,0)#输入图像
    最小匹配=10
    #筛分检测器
    sift=cv2.xfeature2d.sift_create()
    #使用SIFT提取关键点和描述符
    kps1,des1=筛选、检测和计算(img1,无)
    kps2,des2=筛选、检测和计算(img2,无)
    法兰索引KDTREE=0
    索引参数=dict(算法=FLANN\u索引树,树=5)
    搜索参数=dict(检查=50)
    flann=cv2.FlannBasedMatcher(索引参数、搜索参数)
    匹配=法兰N.knnMatch(des1、des2、k=2)
    #按照Lowe比率存储所有良好匹配(g_匹配)
    g_匹配=[]
    对于匹配中的m,n:
    如果m.距离<0.7*n.距离:
    g_匹配追加(m)
    如果len(g_匹配)>min_匹配:
    src_pts=np.float32([kps1[m.queryIdx].pt代表g_匹配中的m])。重塑(-1,1,2)
    dst_pts=np.float32([kps2[m.trainIdx].pt代表g_匹配中的m])。重塑(-1,1,2)
    M、 掩模=cv2.findHomography(src_pts,dst_pts,cv2.RANSAC,5.0)
    matchesMask=mask.ravel().tolist()
    h、 w=img1.1形状
    pts=np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]])。重塑(-1,1,2)
    dst=cv2.透视变换(pts,M)
    img2=cv2.多段线(img2[np.int32(dst)],真,(0255255),3,cv2.线_AA)
    其他:
    打印“未找到足够的匹配项!-%d/%d”%(len(g_匹配项),min_匹配项)
    matchesMask=None
    绘图参数=dict(匹配颜色=(0255255),
    单点颜色=(0255,0),
    matchesMask=matchesMask,#仅限内部服务器
    旗帜=2)
    #区域角
    cpoints=np.int32(dst)
    a、 b,c=cpoints.shape
    #重塑为标准格式
    c_p=c点。重塑((b,a,c))
    #作物匹配区
    匹配区域=裁剪区域