Image processing 如何查找两个图像之间的所有共享区域
我一直在努力寻找一些东西,可以自动找到两幅图像之间的所有共享区域,这显然不是基于像素匹配或差异,经过一段时间的搜索,我基本上什么都没有找到 假设我有以下两张图片,在本例中是网站截图。第一个是“基线”: 第二个非常相似,但是有一些修改过的CSS,所以整个块都被移动了。没有文字内容更改,没有框尺寸更改,只有一些元素重新定位: 在这种情况下(但也确实是每隔一种情况下,其中一个图像是另一个图像的派生图像进行比较),它们的像素差异实际上对于观察变化是无用的: 事实上,即使我们应用一些简单的diff夸张,结果仍然是相当无用的,因为我们仍然在查看像素diff,而不是基于变化的diff,因此我们(无论如何)不会查看对视觉信息的实际修改: 因此,这就像比较两本书,然后根据Image processing 如何查找两个图像之间的所有共享区域,image-processing,Image Processing,我一直在努力寻找一些东西,可以自动找到两幅图像之间的所有共享区域,这显然不是基于像素匹配或差异,经过一段时间的搜索,我基本上什么都没有找到 假设我有以下两张图片,在本例中是网站截图。第一个是“基线”: 第二个非常相似,但是有一些修改过的CSS,所以整个块都被移动了。没有文字内容更改,没有框尺寸更改,只有一些元素重新定位: 在这种情况下(但也确实是每隔一种情况下,其中一个图像是另一个图像的派生图像进行比较),它们的像素差异实际上对于观察变化是无用的: 事实上,即使我们应用一些简单的diff夸
n
的值的多少来决定书是不同的,我们可以找到哪个book1.letters[n]!=书2.字母[n]
所以,我要寻找的是一种计算相似区域的方法,显示两幅图像的哪些部分编码相同的信息,但不一定在相同的边界框中
例如,在上述两幅图像中,几乎所有的数据都是相同的,只是一些部分被重新定位。唯一真正的区别是有神秘的空白
具有类似区域的颜色编码:
以及信件:
我找不到一个工具来实现这一点,甚至找不到允许使用opencv或类似技术实现这一点的教程。也许我在寻找错误的术语,也许从来没有人为此编写过图像比较工具(这似乎难以置信),所以冒着脱离主题的风险:我尽我所能,在这里。如果我需要这个工具,可以作为QA/测试的普通(开源)工具链的一部分运行,那么我有什么选择?(所以:对于同样昂贵的商业软件来说,不是一些昂贵的插件)。建议: 如果你能够分割出蓝色的句子,这个问题就可以大大缓解,这可以通过形态学膨胀和二值化来实现。如果扩展足够强,所有字符都可以接触(尽管不同的文本行保持分开),则连接的组件标签可以提取孔线 现在有了边界框,要尝试的位置数量大大减少 还可以看看diff算法,它可能与顺序文本相关
以下是对初始区域聚类的建议 首先,我们减去这两幅图像,找出不同的区域。然后我们将其调整为更小的规模,以实现更快的速度和更容易的集群 然后我们运行形态学关闭操作将所有附近的对象聚集在一起 将结果设置为阈值,以获得强信号 运行“连接的零部件分析”以获取所有边界框 然后检查所有长方体交点并将其联合。在我的例子中,我只是在实体模式下重新绘制所有边界框,然后重新分析组件以获得区域 一旦我们有了这个,我们可以在第二张图像上运行相同的过程,并使用简单的互相关匹配方法或任何其他奇特的匹配方法对提取的每个区域进行交叉匹配。在这种情况下,区域之间的简单宽度和高度匹配也可以 这是我写的代码。我希望有帮助
import cv2
import numpy as np
# Function to fill all the bounding box
def fill_rects(image, stats):
for i,stat in enumerate(stats):
if i > 0:
p1 = (stat[0],stat[1])
p2 = (stat[0] + stat[2],stat[1] + stat[3])
cv2.rectangle(image,p1,p2,255,-1)
# Load image file
img1 = cv2.imread('img1.jpg',0)
img2 = cv2.imread('img2.jpg',0)
# Subtract the 2 image to get the difference region
img3 = cv2.subtract(img1,img2)
# Make it smaller to speed up everything and easier to cluster
small_img = cv2.resize(img3,(0,0),fx = 0.25, fy = 0.25)
# Morphological close process to cluster nearby objects
fat_img = cv2.dilate(small_img, None,iterations = 3)
fat_img = cv2.erode(fat_img, None,iterations = 3)
fat_img = cv2.dilate(fat_img, None,iterations = 3)
fat_img = cv2.erode(fat_img, None,iterations = 3)
# Threshold strong signals
_, bin_img = cv2.threshold(fat_img,20,255,cv2.THRESH_BINARY)
# Analyse connected components
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(bin_img)
# Cluster all the intersected bounding box together
rsmall, csmall = np.shape(small_img)
new_img1 = np.zeros((rsmall, csmall), dtype=np.uint8)
fill_rects(new_img1,stats)
# Analyse New connected components to get final regions
num_labels_new, labels_new, stats_new, centroids_new = cv2.connectedComponentsWithStats(new_img1)
labels_disp = np.uint8(200*labels/np.max(labels)) + 50
labels_disp2 = np.uint8(200*labels_new/np.max(labels_new)) + 50
cv2.imshow('diff',img3)
cv2.imshow('small_img',small_img)
cv2.imshow('fat_img',fat_img)
cv2.imshow('bin_img',bin_img)
cv2.imshow("labels",labels_disp)
cv2.imshow("labels_disp2",labels_disp2)
cv2.waitKey(0)
不幸的是,我不能产生准确的预期结果,但通过一个相当简单的算法,我得到了一些接近。一般算法为:
该矩阵的一个例子在图1的中间窗格中给出。此图像的尺寸必须与图像1和图像2相同
## read in the images
img1 <- readJPEG('./img1.jpg')
img2 <- readJPEG('./img2.jpg')
## grayscale the images
img1 <- (img1[,,1]+img1[,,2]+img1[,,3])/3
img2 <- (img2[,,1]+img2[,,2]+img2[,,3])/3
## rotate the images for more intuitive R plotting
img1 <- t(apply(img1,2,rev))
img2 <- t(apply(img2,2,rev))
## create some uniform noise
noise <- matrix(runif(n=nrow(img1)*ncol(img1)),nrow=nrow(img1),ncol=ncol(img1))*0.1
## add the SAME noise to both images
img1 <- noise+img1
img2 <- noise+img2
## remove the mean from both images (this may not be necessary)
img1 <- img1/mean(img1)
img2 <- img2/mean(img2)
## Take the conjugate of the fft of the second image
IMG2c <- Conj(fft(img2))
## define how to loop through the first image
row.step=50
col.step=50
## create a zero image (made with all 0s)
zero.img <- matrix(0,ncol=ncol(img1),nrow=nrow(img1))
## initialize some vectors to hold the x and y
## shifts that correspond to the highest phase correlation value
shift.x.vec=NULL
shift.y.vec=NULL
## keep track of how many iterations you go through
i.iters=1
## loop over the columns
i=1
while((i+col.step-1)<nrow(img1)) {
## keep track of how many iterations you go through
j.iters=1
## loop over the rows
j=1
while((j+col.step-1)<ncol(img1)) {
## define a current 'box' as the zero image
cbox1 <- zero.img
## then populate a small box with values from image 1
cbox1[i:(i+row.step-1),j:(j+col.step-1)] <- img1[i:(i+row.step-1),j:(j+col.step-1)]
## PERFORM THE PHASE CORRELATION
## go into the frequency domain
CBOX1 <- fft(cbox1)
## find a normalized value
norm <- abs(CBOX1 * IMG2c)
## perform the phase correlation and go back to the space domain
corr <- Re(fft((CBOX1 * IMG2c)/norm,inv=TRUE)/length(CBOX1))
## this rearranges the quadrants of the matrix see
## matlabs function fftshift
corr <- fftshift(corr)
## find the x and y index values associated with the
## highest correlation value.
shift <- which(corr==max(corr),arr.ind=TRUE)
shift.x <- shift[1]
shift.y <- shift[2]
## populate the x and y shift vectors
shift.x.vec <- c(shift.x.vec,shift.x)
shift.y.vec <- c(shift.y.vec,shift.y)
## THIS IS ADDITIONAL PLOTTING AND CAN BE IGNORED
if(i.iters==6 & j.iters==6) {
dev.new()
##jpeg('./example.jpeg',width=900,height=700)
split.screen(c(1,3))
screen(1)
image(1:nrow(img1),1:ncol(img1),img1,col=gray.colors(200),axes=FALSE,ylab="",xlab="",useRaster=TRUE,main='Noisy Image 1')
rect(j,i,(j+col.step-1),(i+row.step-1))
screen(2)
image(cbox1,col=gray.colors(200),axes=FALSE,useRaster=TRUE,main='Current Box')
screen(3)
image(img2,col=gray.colors(200),axes=FALSE,useRaster=TRUE,main='Noisy Image 2')
##dev.off()
}
j.iters=j.iters+1
j=j+row.step
}
i.iters=i.iters+1
i=i+col.step
}
## make a matrix of shifts values
## in this example, only the y shifts are interesting though
shift.x.mat <- matrix(shift.x.vec,ncol=j.iters-1,nrow=i.iters-1,byrow=TRUE)
shift.y.mat <- matrix(shift.y.vec,ncol=j.iters-1,nrow=i.iters-1,byrow=TRUE)
##jpeg('./final.jpeg',width=800,height=800)
image(shift.y.mat,axes=FALSE,useRaster=TRUE)
##dev.off()