Python 如何为这些';简单';图像?

Python 如何为这些';简单';图像?,python,image-processing,graph,overlap,Python,Image Processing,Graph,Overlap,TLDR: 需要帮助计算两个图形之间的重叠区域 因此,我尝试缝合这两幅图像: 因为我知道我将要缝合的图像肯定来自同一个图像,我觉得我应该能够自己编写代码。对于我来说,使用像OpenCV这样的库来完成这项任务感觉有点过头了 我目前的想法是,我可以通过对每个图像执行以下步骤来简化此任务: 使用PIL加载图像 将图像转换为黑白(PIL图像模式“L”) [可选:通过肉眼检查将图像裁剪到重叠区域] 创建向量行\u和,它是每行的和 [可选:logrow\u sum,以减少我们正在处理的值的大小] 绘制行

TLDR: 需要帮助计算两个图形之间的重叠区域

因此,我尝试缝合这两幅图像:

因为我知道我将要缝合的图像肯定来自同一个图像,我觉得我应该能够自己编写代码。对于我来说,使用像OpenCV这样的库来完成这项任务感觉有点过头了

我目前的想法是,我可以通过对每个图像执行以下步骤来简化此任务:

  • 使用PIL加载图像
  • 将图像转换为黑白(PIL图像模式“L”)
  • [可选:通过肉眼检查将图像裁剪到重叠区域]
  • 创建向量
    行\u和
    ,它是每行的和
  • [可选:log
    row\u sum
    ,以减少我们正在处理的值的大小]
  • 绘制行和
  • 这将减少(潜在的)(3×2)维问题,将2D图像上每个像素的3个RGB通道减少为(1×2)-D问题,取而代之的是2D图像的黑白像素。然后,跨行求和将此问题简化为一维问题

    我使用以下代码来实现上述功能:

    import matplotlib.pyplot as plt
    import numpy as np
    from PIL import Image
    
    class Stitcher():
        def combine_2(self, img1, img2):
            # thr1, thr2 = self.get_cropped_bw(img1, 115, img2, 80)
            thr1, thr2 = self.get_cropped_bw(img1, 0, img2, 0)
            
            row_sum1 = np.log(thr1.sum(1))
            row_sum2 = np.log(thr2.sum(1))
            
            self.plot_4x4(thr1, thr2, row_sum1, row_sum2)
        
        def get_cropped_bw(self, img1, img1_keep_from, img2, img2_keep_till):    
            im1 = Image.open(img1).convert("L")
            im2 = Image.open(img2).convert("L")
            
            data1 = (np.array(im1)[img1_keep_from:] 
                    if img1_keep_from != 0 else np.array(im1))
            data2 = (np.array(im2)[:img2_keep_till] 
                    if img2_keep_till != 0 else np.array(im2))
            
            return data1, data2
        
        def plot_4x4(self, thr1, thr2, row_sum1, row_sum2):
            fig, ax = plt.subplots(2, 2, sharey="row", constrained_layout=True)
            
            ax[0, 0].imshow(thr1, cmap="Greys")
            ax[0, 1].imshow(thr2, cmap="Greys")
            
            ax[1, 0].plot(row_sum1, "k.")
            ax[1, 1].plot(row_sum2, "r.")
            
            ax[1, 0].set(
                xlabel="Index Value",
                ylabel="Row Sum",
            )
            
            plt.show()
    
    
    imgs = (r"combine\imgs\test_image_part_1.jpg",
            r"combine\imgs\test_image_part_2.jpg")
    
    s = Stitcher()
    s.combine_2(*imgs)
    
    这给了我这个图表:

    (我已经在这些黄色框中添加了,以指示重叠区域。)

    这正是我被困的地方。我想确切地找到:

  • 第1张图像的黄色框左侧的索引值,以及
  • 第二幅图像黄色框右侧的索引值
  • 我将重叠区域定义为第一个图形的结束与第二个图形的开始“匹配”的最长范围。对于查找重叠区域的方法,如果行和值不完全相同(如果其中一个按某个因子缩放),我应该怎么做


    我觉得这可能是一个问题,可以使用点积来找到两个图形之间的相似性?但是我想不出如何实现这一点。

    我从中得到了比我预期的更多的乐趣。我是用opencv写的,但那只是为了加载和显示图像。其他一切都是用numpy完成的,所以将其交换到PIL应该不会太困难

    我在用蛮力匹配器。我还编写了一个随机启动hillclimber,它运行的时间要短得多,但我不能保证它会找到正确的答案,因为梯度空间不是平滑的。我不会把它包含在我的代码中,因为它很长而且很简陋,但是如果你真的需要时间效率,我可以稍后再添加它

    我在图像中添加了随机作物和一些椒盐噪声来测试鲁棒性

    蛮力匹配器的工作原理是,我们不知道两幅图像的哪个部分重叠,所以我们需要从左到右、从上到下将较小的图像卷积到较大的图像上。这意味着我们的搜索空间是:

    horizontal = small_width + big_width
    vertical = small_height + big_height
    area = horizontal * vertical
    
    这将随着图像大小的增加而快速增长。我通过给它一个更大的重叠点来激励算法,但它会因为重叠区域的颜色差异而丢失更多的点

    下面是一些执行此程序的图片

    导入cv2
    将numpy作为np导入
    随机输入
    #随机剪边
    def randCrop(图像,最大边距):
    c=[random.randint(0,maxMargin)表示范围(4)];
    返回图像[c[0]:-c[1],c[2]:-c[3];
    #给图像添加噪声
    def saltPepper(图像、minNoise、maxNoise):
    h、 w=图像。形状;
    randNum=random.randint(minNoise,maxNoise);
    对于范围内的(随机数):
    x=random.randint(0,w-1);
    y=随机随机随机数(0,h-1);
    image[y,x]=random.randint(0255);
    返回图像;
    #评估布局
    def getScore(一,二):
    #做原始减法
    左=一-二;
    右=二-一;
    sub=np.最小值(左、右);
    返回np.count_非零(sub);
    #返回范围内的二维随机位置
    def randPos(img,大_形):
    th,tw=大_形;
    h、 w=img.形状;
    x=随机随机随机数(0,tw-w);
    y=随机随机随机数(0,th-h);
    返回[x,y];
    #将小图像叠加到大图像上
    def覆盖层(小、大、位置):
    #打开
    h、 w=小形状;
    x、 y=位置;
    #复制并放置
    copy=big.copy();
    复制[y:y+h,x:x+w]=小;
    返回副本;
    #计算重叠区域
    def重叠(一、二、一、二):
    #打开
    h1,w1=一个形状;
    h2,w2=两个形状;
    x1,y1=位置1;
    x2,y2=位置2;
    #定边
    l1=x1;
    l2=x2;
    r1=x1+w1;
    r2=x2+w2;
    t1=y1;
    t2=y2;
    b1=y1+h1;
    b2=y2+h2;
    #去
    左=最大值(l1,l2);
    右=最小值(r1,r2);
    顶部=最大值(t1,t2);
    底部=最小值(b1,b2);
    返回[左、右、上、下];
    #覆盖+getScore的包装器
    def满分(一、二、一、二、空):
    #检查位置
    x、 y=位置2;
    h、 w=两个形状;
    th,tw=大的空形状;
    如果y+h>th或x+w>tw或x<0或y<0:
    返回-9999999;
    #覆盖层
    temp_one=叠加(一,大,空,位置);
    temp_two=叠加(两个,大的为空,位置为二);
    #重叠
    l、 r,t,b=重叠(一,二,位置一,位置二);
    温度=温度[t:b,l:r];
    温度二=温度二[t:b,l:r];
    #得分
    差异=得分(一级、二级);
    得分=(r-l)*(b-t);
    分数-=diff*2;
    返回分数;
    #使用暴力
    def bruteForce(一,二):
    #计算搜索空间
    #开箱尺寸
    h、 w=一个形状;
    一个尺寸=h*w;
    h、 w=两个形状;
    两个_尺寸=h*w;
    #大大小小
    如果一个尺寸<两个尺寸:
    小=一;
    大=两个;
    其他:
    小=两个;
    大=一;
    #开箱尺寸
    sh,sw=小的形状;
    bh,bw=big.shape;
    总宽度=bw+sw*2;
    总高度=bh+sh*2;
    #设置空图像
    空=np.0((总高度,总宽度),np.uint8);
    #创全球最佳
    最佳得分=-999999;
    最佳位置=无;
    #开始滚动
    伊布