2016-07-12 78 views
2

我目前使用opencv(CV2)和Python Pillow圖像庫嘗試拍攝任意手機的圖像,並用新圖像替換屏幕。我已經到了可以拍攝圖像並識別手機屏幕並獲得角落所有座標的位置,但我很難用新圖像替換圖像中的該區域。如何使用Python替換圖像中的輪廓(矩形)和新圖像?

的代碼,我到目前爲止有:

import cv2 
from PIL import Image 

image = cv2.imread('mockup.png') 
edged_image = cv2.Canny(image, 30, 200) 

(contours, _) = cv2.findContours(edged_image.copy(), cv2.RETR_TREE,  cv2.CHAIN_APPROX_SIMPLE) 
contours = sorted(contours, key = cv2.contourArea, reverse = True)[:10] 
screenCnt = None 

for contour in contours: 
    peri = cv2.arcLength(contour, True) 
    approx = cv2.approxPolyDP(contour, 0.02 * peri, True) 

    # if our approximated contour has four points, then 
    # we can assume that we have found our screen 
    if len(approx) == 4: 
     screenCnt = approx 
     break 

cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 3) 
cv2.imshow("Screen Location", image) 
cv2.waitKey(0) 

這將使我看起來像這樣的圖像:enter image description here

我還可以得到使用這行代碼的屏幕角的座標:

screenCoords = [x[0].tolist() for x in screenCnt] 
// [[398, 139], [245, 258], [474, 487], [628, 358]] 

但是我想不出我的生活中如何採取新的圖像,並將其擴展到我已經找到了座標空間的形狀和,可欣賞唉圖像ontop。

我的猜測是,我可以通過使用此功能,我改編自this stackoverflow question在枕頭的圖像變換做到這一點:

def find_transform_coefficients(pa, pb): 
"""Return the coefficients required for a transform from start_points to end_points. 

    args: 
     start_points -> Tuple of 4 values for start coordinates 
     end_points --> Tuple of 4 values for end coordinates 
""" 
matrix = [] 
for p1, p2 in zip(pa, pb): 
    matrix.append([p1[0], p1[1], 1, 0, 0, 0, -p2[0]*p1[0], -p2[0]*p1[1]]) 
    matrix.append([0, 0, 0, p1[0], p1[1], 1, -p2[1]*p1[0], -p2[1]*p1[1]]) 

A = numpy.matrix(matrix, dtype=numpy.float) 
B = numpy.array(pb).reshape(8) 

res = numpy.dot(numpy.linalg.inv(A.T * A) * A.T, B) 
return numpy.array(res).reshape(8) 

但是我在我頭上了一下,我不能獲得詳細信息。有人能給我一些幫助嗎?

編輯

好了,現在我使用的getPerspectiveTransform和warpPerspective功能,我有以下附加代碼:

screenCoords = numpy.asarray(
    [numpy.asarray(x[0], dtype=numpy.float32) for x in screenCnt], 
    dtype=numpy.float32 
) 

overlay_image = cv2.imread('123.png') 
overlay_height, overlay_width = image.shape[:2] 

input_coordinates = numpy.asarray(
    [ 
     numpy.asarray([0, 0], dtype=numpy.float32), 
     numpy.asarray([overlay_width, 0], dtype=numpy.float32), 
     numpy.asarray([overlay_width, overlay_height],  dtype=numpy.float32), 
     numpy.asarray([0, overlay_height], dtype=numpy.float32) 
    ], 
    dtype=numpy.float32, 
) 

transformation_matrix = cv2.getPerspectiveTransform(
    numpy.asarray(input_coordinates), 
    numpy.asarray(screenCoords), 
) 

warped_image = cv2.warpPerspective(
    overlay_image, 
    transformation_matrix, 
    (background_width, background_height), 
) 
cv2.imshow("Overlay image", warped_image) 
cv2.waitKey(0) 

圖像是越來越旋轉和扭曲正常(我認爲) ,但與屏幕尺寸不一樣。它的「短」:

enter image description here

,如果我使用不同的圖像,這是非常高的垂直我最終的東西是太「長」:

enter image description here

我需要應用額外的轉換來縮放圖像?不知道這裏發生了什麼,我認爲透視變換會使圖像自動縮放到提供的座標。

回答

0

可以通過

import cv2 
A_img = cv2.imread("new_image.png") 
B_img = cv2.imread("larger_image.jpg") 
x_offset=y_offset=50 
B_img[y_offset:y_offset+A_img.shape[0], x_offset:x_offset+A_img.shape[1]] = A_img 

覆蓋新圖像(旋轉篩選電話的取向)到原圖像可以具有如果需要新的圖像適當地alpha通道旋轉。

正如您在下面的評論(標題透視轉換下)中提到的那樣,新圖像需要透視轉換(扭曲)。查看下面的鏈接,瞭解透視變換如何將畸變圖像修復爲直線(您希望得到相反的效果)。

http://docs.opencv.org/master/da/d6e/tutorial_py_geometric_transformations.html#gsc.tab=0 

您基本上需要在原始和扭曲的空間(pts1和pts2)中提供4個點用於轉換。

我想你可能會使用原始圖像的四角插入(pts1)和輪廓角(pts2)應該工作。

+0

我不認爲雖然這徹底解決了這個問題。我在圖像中找到的屏幕通常不是一個完美的矩形,因此旋轉圖像是不夠的,我還需要轉換透視圖以使其與我找到的輪廓相匹配。那有意義嗎? –

+0

你可以做一個反向透視轉換 – user3404344

+0

你能給我更多的細節嗎?我是一個完整的noob opencv,圖像處理和向量數學 –

1

我下載了您的圖片數據,並在本地機器中重現了問題以找出解決方案。還下載了lenna.png以適應手機屏幕。

import cv2 
import numpy as np 

# Template image of iPhone 
img1 = cv2.imread("/Users/anmoluppal/Downloads/46F1U.jpg") 
# Sample image to be used for fitting into white cavity 
img2 = cv2.imread("/Users/anmoluppal/Downloads/Lenna.png") 

rows,cols,ch = img1.shape 

# Hard coded the 3 corner points of white cavity labelled with green rect. 
pts1 = np.float32([[201, 561], [455, 279], [742, 985]]) 
# Hard coded the same points on the reference image to be fitted. 
pts2 = np.float32([[0, 0], [512, 0], [0, 512]]) 

# Getting affine transformation form sample image to template. 
M = cv2.getAffineTransform(pts2,pts1) 

# Applying the transformation, mind the (cols,rows) passed, these define the final dimensions of output after Transformation. 
dst = cv2.warpAffine(img2,M,(cols,rows)) 

# Just for Debugging the output. 
final = cv2.addWeighted(dst, 0.5, img1, 0.5, 1) 
cv2.imwrite("./garbage.png", final) 

enter image description here

+0

我很驚訝這爲你工作。我嘗試了完全相同的代碼(沒有硬編碼值),並且我繼續得到縮放比例的圖像(請參閱我的問題的編輯版本中的圖片)。我認爲它只對你有效,因爲你對價值進行了硬編碼。 –

+0

Aaaah ....我在我的代碼中有一個錯誤。你說得對,我錯了。即將發佈完整的解決方案。 –

+0

是的,您可以將此標記爲答案,供任何未來的訪問者使用。同時編輯您的問題,使其小而精確。這樣它可以幫助社區。 – ZdaR