Как отделить отфотошопленную часть от остальной части изображения, если задано исходное изображение?

#python #numpy #opencv #image-processing

#python #тупой #opencv #обработка изображений

Вопрос:

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

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

Поэтому я заменяю обычную cv2.threshold() функцию, которая добавляет значения 4-связанных соседей пикселя и сравнивает их с пороговым значением.

Это моя пороговая функция :

 def threshold(image,thresh):
    b,g,r= cv2.split(image)
    res=np.zeros(b.shape,dtype=np.uint8)

    #Not considering boundary pixels for the binary image
    for i in range(1,b.shape[0]-1):
        for j in range(1,b.shape[1]-1):
            sumb = b[i][j]   b[i 1][j]   b[i-1][j]   b[i][j 1]   b[i][j-1] 
            sumg = g[i][j]   g[i 1][j]   g[i-1][j]   g[i][j 1]   g[i][j-1] 
            sumr = r[i][j]   r[i 1][j]   r[i-1][j]   r[i][j 1]   r[i][j-1] 

            res[i][j]=255 if sumb<=5*thresh or sumg<=5*thresh or sumr<=5*thresh else 0

    res=res[1:-1,1:-1]
    res=cv2.copyMakeBorder(res,1,1,1,1,cv2.BORDER_REFLECT_101)
    return res
 

Это дает лучшие результаты, но не такие хорошие, как ожидалось.

Например, это подлинное изображение:

оригинал

Это склеенное изображение:

склеенный

Это пороговое изображение (я обнаружил, что thresh=2 это оптимальное значение):

пороговое значение

Я попытался удалить небольшие компоненты, удалив компоненты с использованием нескольких белых пикселей connectedComponentsWithStats() .

Это границы после удаления небольших связанных компонентов:

границы

в то время как ожидаемое изображение:

ожидаемый

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

Как я могу получить лучшие результаты, чем эти?

Кроме того, можно ли оптимизировать мою threshold функцию? Прямо сейчас на обработку одного изображения уходит не менее 2 секунд!

Комментарии:

1. Интересная статья доктора Нила Краветца о подделке фотографий здесь … hackerfactor.com/papers/bh-usa-07-krawetz-wp.pdf

2. JPEG (т. Е. сжатие изображения с потерями / шумом, вероятно, усложняет задачу.

Ответ №1:

[У меня сейчас не установлен OpenCV на моем компьютере, поэтому вместо этого я просмотрел ваши изображения в MATLAB. Приведенный ниже код Python не тестировался.]

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

 res = cv2.absdiff(image,thresh)
 

Если вы отобразите это (с некоторой контрастностью), вы увидите:

абсолютная разница между двумя изображениями

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

Давайте возьмем максимум по R, G, B для каждого пикселя:

 res = np.amax(res, axis=2)   # (I think OpenCV stores the channels in the 3rd dimension?)
 

Я обнаружил, что большинство артефактов сжатия ниже 15, поэтому давайте установим пороговое значение:

 res = res > 15
 

Наконец, примените свой cv2.medianBlur() , чтобы удалить последние биты шума. Вы также можете попробовать применить GaussianBlur() до порога.

Комментарии:

1. Ваши 3 строки кода сработали как по волшебству! Я пробовал то же самое очень непитоновским способом — проверял, было ли значение каждого канала для каждого пикселя больше 15 (используя вложенные циклы for ). Я не думаю, что получил тот же результат. Вероятно, какая-то ошибка в моей логике. Большое спасибо!

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

3. @AbdulMuizz: Вы рассматриваете соседние пиксели с помощью фильтра. Я бы предположил GaussianBlur , что тогда вы, вероятно, можете снизить порог.