2016-07-12 8 views
2

Ich benutze derzeit die Bildbibliothek opencv (CV2) und Python Pillow, um ein Bild von beliebigen Telefonen zu erstellen und den Bildschirm durch ein neues Bild zu ersetzen. Ich bin an den Punkt gekommen, wo ich ein Bild machen und den Bildschirm des Telefons identifizieren kann und alle Koordinaten für die Ecke bekommen kann, aber es fällt mir sehr schwer, diesen Bereich im Bild durch ein neues zu ersetzen.Wie ersetzt man eine Kontur (Rechteck) in einem Bild mit einem neuen Bild mit Python?

Der Code habe ich bisher:

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) 

Das ist mir ein Bild geben, das wie folgt aussieht: enter image description here

ich auch die Koordinaten der Bildschirmecken mit dieser Zeile Code bekommen:

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

jedoch habe ich nicht für das Leben von mir herausfinden, wie ein neues Bild zu nehmen und es in die Form des Raumkoordinatenmaßstabs ich gefunden habe und overl ay das Bild ontop.

Meine Vermutung ist, dass ich das tun kann, ein Bild umwandeln in Kissen mit dieser Funktion, die ich von this stackoverflow question angepasst:

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) 

Jedoch habe ich in über meinem Kopf bin ein bisschen, und ich kann nicht Informiere dich über die Details. Könnte mir jemand helfen?

EDIT

Ok jetzt, dass ich die getPerspectiveTransform und warpPerspective Funktionen verwenden, habe ich die folgenden zusätzlichen Code bekam:

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) 

Das Bild wird gedreht zu werden und verzerrt richtig (glaube ich) , aber es ist nicht die gleiche Größe wie der Bildschirm. Seine „kürzer“:

enter image description here

und wenn ich ein anderes Bild verwenden, das sehr groß vertikal ist ich am Ende mit etwas, das zu „lang“ ist:

enter image description here

Muß ich eine zusätzliche Transformation anwenden, um das Bild zu skalieren? Ich bin mir nicht sicher, was hier vor sich geht, ich dachte, die perspektivische Transformation würde das Bild automatisch auf die angegebenen Koordinaten skalieren lassen.

Antwort

0

Sie können das neue Bild überlagern (gedrehte Orientierung des Telefons zu screenen) auf das Originalbild durch

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 

Sie das neue Bild mit Alpha-Kanal entsprechend gedreht, falls erforderlich machen können.

Wie Sie im folgenden Kommentar (unter der Überschrift perspektivische Transformation) erwähnt haben, muss das neue Bild perspektivisch transformiert (verzerrt) werden. Sehen Sie im folgenden Link nach, wie die perspektivische Transformation funktioniert, um das verzerrte Bild auf "gerade" zu bringen (Sie möchten das Gegenteil davon).

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

Sie müssen grundsätzlich 4 Punkte in dem ursprünglichen und verzerrten Raum zur Verfügung zu stellen (PTS1 und PTS2) für die Transformation.

Ich glaube, Sie könnten die vier Ecken des Originalbildes einfügen (pts1) und die Ecken der Konturen (pts2) sollten funktionieren.

+0

Ich denke nicht, das vollständig das Problem löst. Der Bildschirm, den ich im Bild finde, ist normalerweise kein perfektes Rechteck, deshalb ist das Drehen des Bildes nicht ausreichend, ich muss auch die Perspektive so transformieren, dass sie der Kontur entspricht, die ich gefunden habe. Ist das sinnvoll? –

+0

Sie könnten eine umgekehrte perspektivische Transformation tun – user3404344

+0

Könnten Sie mir etwas mehr Details geben? Ich bin ein kompletter Anfänger zu opencv, Bildverarbeitung und Vektor Mathe –

1

Ich habe Ihre Bilddaten heruntergeladen und reproduziert das Problem in meinem lokalen Computer, um die Lösung zu finden. Auch heruntergeladen lenna.png, um in den Telefonbildschirm zu passen. obwohl

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

Ich bin überrascht, das hat für dich funktioniert. Ich habe den exakt gleichen Code (ohne die hartcodierten Werte) ausprobiert und bekomme weiterhin falsche Bilder (siehe Bilder in der bearbeiteten Version meiner Frage). Ich denke, es hat nur für dich funktioniert, weil du Werte fest codiert hast. –

+0

Aaaah .... Ich hatte einen Fehler in meinem Code. Du hast Recht, ich habe mich geirrt. Wird bald die volle Lösung posten. –

+0

Ja sicher, Sie können dies als Antwort für zukünftige Besucher markieren. Bearbeiten Sie auch Ihre Frage, um sie klein und präzise zu machen. Damit es der Community helfen kann. – ZdaR

Verwandte Themen