2017-01-27 13 views
0

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

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

Я скорее использую библиотечную функцию, чем сама реализация этой операции. Кто-нибудь знает, есть ли какая-либо функция библиотеки, которая может выполнять этот тип операции, в opencv или любой другой библиотеке обработки изображений?

ОБНОВЛЕНИЕ:

я обнаружил, что OpenCV warpPerspective может быть использован с borderMode = BORDER_TRANSPARENT, что означает, что пиксели в целевом изображении, соответствующие «выбросы» в исходном изображении не являются измененный функцией. Поэтому я думал, что смогу реализовать эту подпиксельную вставку с помощью всего лишь warpPerspective и адекватной матрицы преобразования. Поэтому я написал эту функцию в Python для выполнения операции:

def insert_patch_subpixel(im, patch, p): 
    """ 
    im: numpy array with source image. 
    patch: numpy array with patch to be inserted into the source image 
    p: tuple with the center of the position (can be float) where the patch is to be inserted. 
    """ 
    ths = patch.shape[0]/2 
    xpmin = p[0] - ths 
    ypmin = p[1] - ths 
    Ho = np.array([[1, 0, xpmin], 
        [0, 1, ypmin], 
        [0, 0,  1]], dtype=float) 

    h,w = im.shape 
    im2 = cv2.warpPerspective(patch, Ho, (w,h), dst=im, 
         flags=cv2.INTER_LINEAR, 
         borderMode=cv2.BORDER_TRANSPARENT) 
    return im2 

К сожалению, интерполяция не похожа на работу для останца пикселей, если BORDER_TRANSPARENT используются. Я тестировал эту функцию с небольшим 10x10-изображением (заполненным значением 30) и вставляя патч 4x4 (заполненный значением 100) при p = (5,5) (левый рисунок) и p = (5.5,5.5) (средний рисунок) и на нижеследующих рисунках видно, что на границе нет интерполяции. Однако, если я изменю boderMode на , BORDER_CONSTANT работает с интерполяцией (рисунок справа), но также заполняет целевое изображение 0s для значений outlier. enter image description here

Это позор, что интерполяция не работает с BORDER_TRANSPARENT. Я предлагаю это как усовершенствование проекта opencv.

+0

Искривление суб-изображение в другой может быть сделано с помощью 'cv2.findHomography()' –

+0

Это может быть излишним для вашей проблемы, но вы можете деформировать патч в Фурье области пространства, то обратное преобразование и объединить его в ваш целевой образ. Если выполнено правильно, что операция дает точность субпикселя –

+0

@ Matt-Mac-Muffin вы могли бы немного подробнее остановиться на этом подходе? – martinako

ответ

1

Я нашел решение, основанное на том, что я нашел в моем обновлении вопроса. Как я мог видеть интерполяцию происходит при использовании boderMode = BORDER_CONSTANT в функции warpPerspective я думал, мог бы использовать это в качестве весовой маски для смешивания между исходным изображением и субпиксельным вставленным пятном на черный фоне. Смотрите новую функцию и тестовый код:

import numpy as np 
import matplotlib.pyplot as plt 

def insert_patch_subpixel2(im, patch, p): 
    """ 
    im: numpy array with source image. 
    patch: numpy array with patch to be inserted into the source image 
    p: tuple with the center of the position (can be float) where the patch is to be inserted. 
    """ 
    ths = patch.shape[0]/2 
    xpmin = p[0] - ths 
    ypmin = p[1] - ths 
    Ho = np.array([[1, 0, xpmin], 
        [0, 1, ypmin], 
        [0, 0,  1]], dtype=float) 

    h,w = im.shape 
    im2 = cv2.warpPerspective(patch, Ho, (w,h), 
         flags=cv2.INTER_LINEAR, 
         borderMode=cv2.BORDER_CONSTANT) 

    patch_mask = np.ones_like(patch,dtype=float) 
    blend_mask = cv2.warpPerspective(patch_mask, Ho, (w,h), 
         flags=cv2.INTER_LINEAR, 
         borderMode=cv2.BORDER_CONSTANT) 

    #I don't multiply im2 by blend_mask because im2 has already 
    #been interpolated with a zero background. 
    im3 = im*(1-blend_mask)+im2 
    im4 = cv2.convertScaleAbs(im3) 
    return im4 

if __name__ == "__main__": 
    x,y = np.mgrid[0:10:1, 0:10:1] 
    im =(x+y).astype('uint8')*5 
    #im = np.ones((10,10), dtype='uint8')*30 
    patch = np.ones((4,4), dtype='uint8')*100 
    p=(5.5,5.5) 
    im = insert_patch_subpixel2(im, patch, p) 
    plt.gray() 
    plt.imshow(im, interpolation='none', extent = (0, 10, 10, 0)) 
    ax=plt.gca() 
    ax.grid(color='r', linestyle='-', linewidth=1) 
    ax.set_xticks(np.arange(0, 10, 1)); 
    ax.set_yticks(np.arange(0, 10, 1)); 
    def format_coord(x, y): 
     col = int(x) 
     row = int(y) 
     z = im[row,col] 
     return 'x=%1.4f, y=%1.4f %s'%(x, y, z) 
    ax.format_coord = format_coord 
    plt.show() 

На изображениях ниже мы можем увидеть результаты теста с небольшим 10х10 изображения (заполняется со значением 30) и вставив 4x4 патч (заполняется значением 100) в p = (5,5) (левая цифра) и p = (5.5,5.5) (средняя цифра), и теперь мы можем видеть на рисунках ниже, что на границе есть билинейная интерполяция. Чтобы показать, что интерполяция работает с произвольным фоном, я также показываю тест с градиентным фоном 10x10 (правый рисунок). Сценарий тестирования создает цифру, которая позволяет проверять значения пикселей и проверять правильность интерполяции на каждом пикселе границы. enter image description here

2

Измените размер изображения патча до нужного размера в пункте назначения. Затем установите альфа по краям на основе 1,0 - фракции для левого края, фракции для правого края. Затем смешайте.

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

+0

Спасибо, я вижу, как это будет сделано, чтобы сделать патч-смесь с окружением, но пиксели внутри патча все равно будут помещены в целые местоположения. Если я сначала не сменю патч с дробной частью местоположения. – martinako

+0

Я думаю, что мне придется реализовать альфа-смесь вручную, я думаю, что opencv имеет функцию addWeighted для смешивания полных изображений, но она не позволяет маскировать – martinako

1

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

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

Эта функция по существу делает только перевод (подпиксель).