как найти все общие области между двумя изображениями - PullRequest
0 голосов
/ 06 декабря 2018

Я пытался найти что-то, что автоматически находит все общие области между двумя изображениями, явно , а не на основе сопоставления пикселей или различий, и я в основном ничего не придумываю после довольно многопоиска.

Скажем, у меня есть следующие два изображения, в данном случае, скриншоты сайта.Первая «базовая линия»:

enter image description here

, а вторая очень похожа, но с некоторым измененным CSS, поэтому целые блоки перемещаются.Без изменения текстового содержимого, без изменения размера блока, только некоторые элементы переставлены:

enter image description here

В этом случае (но также буквально в любом другом случае, когда два изображениягде одно является производным от другого, которое нужно сравнивать) их разность пикселей фактически бесполезна для просмотра того, что изменилось:

enter image description here

Фактически, даже еслимы применяем простое преувеличение различий, в результате все еще довольно бесполезен, потому что мы все еще смотрим на разность пикселей, вместо разностей, основанных на том, что изменило , поэтому мы нев любом случае) обратите внимание на фактические изменения визуальной информации:

enter image description here

Так что это похоже на сравнение двух книг, а затем решение о том, что книги различаются на основена сколько значений для n мы можем найти, для которых book1.letters[n] != book2.letters[n] ...

Итак, я ищу способ вычисления областей сходства, показывающий, какие части двух изображений кодируютсята же информация, но не нобязательно в одних и тех же ограничительных полях.

Например, на двух вышеупомянутых изображениях почти все данные одинаковы, только некоторые части перемещены.Единственное истинное отличие состоит в том, что есть загадочные пробелы.

С похожими регионами, кодированными цветом:

enter image description here

и соответствие:

enter image description here

Я не могу найти ни одного инструмента для этого, и я даже не могу найти учебники, которые позволяют реализовать это с использованием opencv или аналогичных технологий.Может быть, я ищу неправильные термины, может быть, никто никогда не писал инструмент для сравнения изображений для этого (что кажется невероятным?), Так что рискуя оказаться не по теме: я искал и исследовал столько, сколько я могу, здесь.Каковы мои варианты, если мне нужно это как инструмент, который можно запустить как часть нормальной (с открытым исходным кодом) цепочки инструментов для QA / тестирования?(так: не какой-нибудь дорогой плагин для столь же дорогого коммерческого программного обеспечения).

Ответы [ 3 ]

0 голосов
/ 06 декабря 2018

Вот предложение для начальной кластеризации областей.

Сначала мы вычитаем 2 изображения, чтобы выяснить, какая область отличается.Затем мы изменяем его размер в меньшем масштабе для ускорения и упрощения кластеризации.

enter image description here

Затем мы запускаем морфологическую операцию закрытия, чтобы объединить все близлежащие объекты.

enter image description here

Порог результата для получения сильных сигналов

enter image description here

Запуск подключенанализ компонентов, чтобы получить все ограничивающие блоки.

enter image description here

Затем проверьте все пересечения блоков и объедините их.В моем случае я просто перерисовал все ограничивающие рамки в твердотельном режиме и повторно проанализировал компонент, чтобы получить регионы

enter image description here

Как только мы получим это, мыможет запустить тот же процесс на втором изображении и сопоставить каждую из областей, извлеченных с использованием простого метода сопоставления с взаимной корреляцией или любого другого необычного метода сопоставления.В этом случае также подойдет простое сопоставление ширины и высоты между регионами.

Вот код, который я сделал.Надеюсь, это поможет.

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)
0 голосов
/ 10 декабря 2018

К сожалению, я не смог дать желаемого результата, но с помощью довольно тупого алгоритма я немного приблизился.Общий алгоритм:

  1. Добавьте один и тот же случайный шум к каждому изображению.

    См. Первую и третью панели на рисунке 1. ДобавлениеОдин и тот же шум на обоих изображениях позволяет сравнивать безликие области (например, белый фон) с помощью фазовой корреляции (ниже).

  2. Заполните матрицу нулей в штучной упаковке подразделом из изображения 1

Пример этой матрицы приведен всредняя панель рисунка 1. Это изображение должно быть того же размера, что и изображение 1 и изображение 2.

Выполните фазовую корреляцию между матрицей из второго шага и зашумленным изображением 2.

Здесь можно повернуть несколько ручек, которые могут улучшить конечный результат.См. Выполнение фазовой корреляции с FFT в R

enter image description here

Извлечение значений x и y 'сдвигов', связанных с наибольшим значением корреляции

Эти значения показывают, как матрица из шага 2 должна быть смещена в x и yнаправления, так что лучше соответствует шумное изображение 2.

Отрегулируйте положение подраздела в штучной упаковке на шаге 3, чтобы все области на зашумленном изображении 1 были зациклены.Затем повторите шаги 3 и 4.

Это делается путем зацикливания строк и столбцов на изображении 1. Вы можете зацикливать каждый индекс или пропускать несколько индексов.

Создайте матрицу из сдвигов x и y и построите график, чтобы увидеть, как области на изображении1 сравниваются с изображением 2.

enter image description here

Обратите внимание, что результат не совсем то, что вы ищете, а его близость.В основном красные области указывают, что соответствующие области на изображении 1 не должны быть сдвинуты.Желтые области (в данном случае) необходимо сместить немного вниз, оранжевые - больше, а белые - сместить вверх.

Опять же, добавление одинакового шума к изображениям 1 и 2 является важным шагом.Алгоритм зависит от выделения небольших областей в штучной упаковке (в примере кода я использовал блоки размером 50x50 пикселей).Когда вы просматриваете строки и столбцы изображения 1 и изолируете соответствующие области в штучной упаковке, некоторые области будут содержать области без элементов.Это создает проблемы в фазовой корреляции, поскольку область без элементов в штучной упаковке будет иметь множество высоких значений корреляции во всех областях, которые имеют одинаковый фон без элементов.Эффективно, добавление шума добавляет функции к обоим изображениям, чтобы уменьшить неоднозначные фазовые корреляции.

Причины, по которым этот алгоритм не дает того же результата, что и требуемый, заключаются в том, что области в штучной упаковке не выбраны умным способом - они выбираются при циклическом цикле по строкам и столбцам изображения 1.Следовательно, в зависимости от выбранного размера блока некоторые области в штучной упаковке будут иметь функции, которые переводятся по-разному по сравнению с изображением 2. Возможно, этот алгоритм будет работать лучше после алгоритма кластеризации областей, предложенного yapws87

Вот код R для получения этих результатов:

## 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()
0 голосов
/ 06 декабря 2018

Предложение:

Проблема может быть значительно облегчена, если вы сможете выделить синие предложения, что может быть достигнуто путем морфологического расширения с последующей бинаризацией.Если расширение достаточно сильное, чтобы все символы соприкасались (хотя отдельные строки текста остаются разрозненными), маркировка подключенных компонентов может выделить линии отверстий.

Теперь у вас есть ограничивающие рамки, и количество позиций, которые нужно попробовать, равнозначительно уменьшен.

Также посмотрите на алгоритм сравнения, который может иметь отношение к последовательному тексту.https://en.wikipedia.org/wiki/Diff

enter image description here

...