Создание линейной маски градиента с использованием opencv или - PullRequest
0 голосов
/ 18 октября 2019

Я пытаюсь сшить изображения прямо сейчас, чтобы создать панорамы. Подход, который я пробовал до сих пор, состоял в том, чтобы деформировать первое изображение и выровнять второе изображение с ним и повторить для n числа изображений. Кажется, это работает нормально, но когда я пытаюсь объединить два изображения вместе, создав двоичную черно-белую маску с использованием нарезки кусочками, возникает определенный шов, который различает два изображения. Я думаю, что если бы у меня была пернатая маска в области, где черный встречается с белым с переходной областью, или даже просто маска с линейным градиентом, идущая от левой стороны изображения к правому перекрестному переходу от черного к белому, этопомочь сделать швы немного лучше. Я попытался использовать Gaussian Blur, чтобы размыть границы моей двоичной маски, экспериментируя с различными размерами ядра, но это как бы ухудшило ситуацию, так как Граница маски начала появляться на изображениях. Я просто не могу понять, как использовать Numpy и OpenCV для создания такой маски и смешивания изображений. Я даже был бы счастлив, если бы я мог создать маску, как показано ниже, чтобы я мог использовать ее, чтобы смешивать изображения для улучшения результатов. Будем признательны за любые предложения

enter image description here enter image description here

Ответы [ 2 ]

1 голос
/ 19 октября 2019

Я могу придумать два способа приблизиться к этому. Основная проблема заключается в том, что Python / OpenCV / Numpy требует, чтобы изображения были одинаковой формы при смешивании.

Первый подход заключается в заполнении двух изображений нулями до окончательного сшитого размера. Затем создайте линейные линейные изменения на желаемом перекрытии и добавьте их слева и справа соответствующим образом с единицами и / или нулями до того же окончательного сшитого размера. Тогда смешайте. Но это большая работа по созданию всего отступа.

Таким образом, более простой подход состоит в том, чтобы просто обрезать изображения на две части каждая: область перекрытия и левая часть левого изображения и область перекрытия иправо на правильное изображение. Затем смешайте области перекрытия. Затем объедините обрезанные изображения соответствующим образом. Это то, что я делаю ниже. Я использую самую большую горную вершину в качестве правой стороны перекрытия и область слева на правом изображении, чтобы определить левую сторону перекрытия. Сначала я увеличил яркость правого изображения, чтобы увидеть, как работает смешение.

import cv2
import numpy as np


# read left and right images
# images from https://medium.com/pylessons/image-stitching-with-opencv-and-python-1ebd9e0a6d78
left = cv2.imread('left.jpg')
right = cv2.imread('right.jpg')

# increase brightness of right image so that the blend difference can be seen after stitching
rightx = 1.5*right
rightx = np.clip((rightx), 0, 255)
rightx = np.uint8(rightx)

# get dimensions
hl, wl, cl = left.shape
hr, wr, cr = right.shape

print("left",hl,wl)
print("right",hr,wr)
#left 710 818
#right 709 816

# note that the two images have different dimensions
# compute min height
hm = min(hl, hr)

# measure mtn peak x location to compute overlap region x end point 
xpl = 603
xpr = 141

# note that everything from the mt peak to the left side of the right image overlaps in the left image
# So use xpr as the ramp width
ramp_width = xpr

# compute start x position of ramp in each image
xrampl = xpl-ramp_width
xrampr = 0

# crop left image into 2 parts horizontally
# start of image to ramp start and ramp start to ramp end 
left1 = left[0:hm, 0:xpl-ramp_width]
left2 = left[0:hm, xpl-ramp_width:xpl]

# crop right image into 2 parts horizontally
# ramp start to ramp end and ramp end to end of image
rightx1 = rightx[0:hm, 0:ramp_width]
rightx2 = rightx[0:hm, ramp_width:wr-ramp_width+1]

# create horizontal ramp down from 1 to 0 over the ramp width for the left image
# convert from one channel to three channels
rampl = np.linspace(1, 0, ramp_width)
rampl = np.tile(np.transpose(rampl), (hm,1))
rampl = cv2.merge([rampl,rampl,rampl])

# create horizontal ramp up from 0 to 1 over the ramp width for the right image
# convert from one channel to three channels
rampr = np.linspace(0, 1, ramp_width)
rampr = np.tile(np.transpose(rampr), (hm,1))
rampr = cv2.merge([rampr,rampr,rampr])

# blend the overlap regions, clip and make into int
blend = left2 * rampl + rightx1 * rampr
blend = np.clip((blend), 0, 255)
blend = np.uint8(blend)

# concatenate the images for the stitched result
stitched = np.concatenate((left1,blend,rightx2), axis=1)

cv2.imshow("left", left)
cv2.imshow("right", right)
cv2.imshow("rightx", rightx)
cv2.imshow("rampl", rampl)
cv2.imshow("rampr", rampr)
cv2.imshow("blend", blend)
cv2.imshow("stitched", stitched)
cv2.waitKey(0)
cv2.destroyAllWindows()

# write result to disk
cv2.imwrite("rightx.jpg", right)
cv2.imwrite("rampl.jpg", np.uint8(255*rampl))
cv2.imwrite("rampr.jpg", np.uint8(255*rampr))
cv2.imwrite("blend.jpg", blend)
cv2.imwrite("left_right_stitch.jpg", stitched)


Исходное левое изображение:

enter image description here

Оригинальное правое изображение:

enter image description here

Яркое правое изображение:

enter image description here

Уменьшение для левого изображения:

enter image description here

Увеличение для правого изображения:

enter image description here

Смешанное изображение для области перекрытия:

enter image description here

Сшитый результат:

enter image description here

1 голос
/ 18 октября 2019

Итак, у меня были / были те же идеи, которые упоминает fmw42 в комментариях , но вместо альфа-смешения я думал о простом линейном смешивании с использованием соответствующих «масок смешения» (которые являются инвертированными масками). вы бы использовали для альфа-смешивания).

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

import cv2
import numpy as np

# Some input images
img1 = cv2.resize(cv2.imread('path/to/your/image1.png'), (400, 300))
img2 = cv2.resize(cv2.imread('path/to/your/image2.png'), (400, 300))

# Generate blend masks, here: linear, horizontal fading from 1 to 0 and from 0 to 1
mask1 = np.repeat(np.tile(np.linspace(1, 0, img1.shape[1]), (img1.shape[0], 1))[:, :, np.newaxis], 3, axis=2)
mask2 = np.repeat(np.tile(np.linspace(0, 1, img2.shape[1]), (img2.shape[0], 1))[:, :, np.newaxis], 3, axis=2)

# Generate output by linear blending
final = np.uint8(img1 * mask1 + img2 * mask2)

# Outputs
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('mask1', mask1)
cv2.imshow('mask2', mask2)
cv2.imshow('final', final)
cv2.waitKey(0)
cv2.destroyAllWindows()

Это входные данные и маски:

Inputs and masks

Это будет вывод:

Output

Линейные "маски смешивания" создаются методом linspace NumPy, а некоторые повторяются с помощью вектораМетоды NumPy tile и repeat. Возможно, эта часть может быть дополнительно оптимизирована.

Предупреждение: по крайней мере для представленного линейного наложения, убедитесь, что для каждого пикселя, который вы генерируете,

mask1[y, x] * img1[y, x] + mask2[y, x] * img2[y, x] 

, что

mask1[y, x] + mask2[y, x] <= 1

или вы можете получить некоторую «передержку» для этих пикселей.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...