web-dev-qa-db-ja.com

Python - 画像からQRコードを検出し、OpenCVを使用してトリミングする

私はPython(3.7)とOpenCVを使用してプロジェクトに取り組んでいます。その上にQRコードを搭載した文書のイメージ(カメラを使ってキャプチャしてください)。

このQRコードには、それぞれ6つの変数があります。

  1. QRコード画像のサイズ

  2. 単位


最新更新:

これが同じ順序で実行する必要があるステップです。

  1. QRコードを検出してサイズ値の読み取りを復号する
  2. したがって、QRコード(画像)のサイズが内部に記載されているサイズに等しくない場合は、両方のサイズ値に等しいサイズを拡大縮小します。
  3. 次に、QRコード内で記載されている値に従って、QRコード画像からすべての側面に向かって画像をトリミングします。

このコードを試してみました:

_def decodeAndCrop(inputImage):
    print(str(inputImage))
    image = cv2.imread(str(inputImage))
    qrCodeDetector = cv2.QRCodeDetector()
    decodedText, points, _ = qrCodeDetector.detectAndDecode(image)
    qr_data = decodedText.split(",")
    print("qr data from fucntion: {}".format(qr_data))
    if points is not None:
        pts = len(points)
    # print(pts)
    for i in range(pts):
        nextPointIndex = (i + 1) % pts
        if str(inputImage) == "scaled_img.jpg":
            cv2.line(
                image,
                Tuple(points[i][0]),
                Tuple(points[nextPointIndex][0]),
                (255, 0, 0),
                5,
            )
        print(points[i][0])
        width = int(
            math.sqrt(
                (points[0][0][0] - points[1][0][0]) ** 2
                + (points[0][0][1] - points[1][0][1]) ** 2
            )
        )
        height = int(
            math.sqrt(
                (points[1][0][0] - points[2][0][0]) ** 2
                + (points[1][0][1] - points[2][0][1]) ** 2
            )
        )
        print("height and width after scaling: {} {}".format(height, width))
        if not str(inputImage) == "scaled_img.jpg":
            scaled_img = None
            if width == qr_data[0] and height == qr_data[0]:
                print("Sizes are equal")
                # Add the extension values to points and crop
                y = int(points[0][0][1]) - int(qr_data[1])
                x = int(points[0][0][0]) - int(qr_data[4])
                roi = image[
                    y : y + height + int(qr_data[3]), x : x + width + int(qr_data[2])
                ]
                scaled_img = cv2.imwrite("scaled_img.jpg", roi)
                return scaled_img
            else:
                print(
                    "Width and height  "
                    + str(width)
                    + "x"
                    + str(height)
                    + "  not equal to "
                    + str(qr_data[0])
                    + "x"
                    + str(qr_data[0])
                )
                if height > int(qr_data[0]):
                    scale_width = int(width) - int(qr_data[0])
                    scale_height = int(height) - int(qr_data[0])
                    print(f"scaled width: {scale_width} scaled height: {scale_height}")
                    dimension = (scale_width, scale_height)
                    scaled_img = cv2.resize(
                        image, dimension, interpolation=cv2.INTER_AREA
                    )
                    print("new img dims: {}".format(scaled_img.shape))
                    cv2.imshow("scaled image:", scaled_img)
                    cv2.imwrite("scaled_img.jpg", scaled_img)
                Elif height < int(qr_data[0]):
                    scale_width = int(qr_data[0]) - width
                    scale_height = int(qr_data[0] - height)
                    print(f"scaled width: {scale_width} scaled height: {scale_height}")
                    dimension = (scale_width, scale_height)
                    scaled_img = cv2.resize(
                        image, dimension, interpolation=cv2.INTER_AREA
                    )
                    print("new img dims: {}".format(scaled_img.shape))
                    cv2.imshow("scaled image:", scaled_img)
                    cv2.imwrite("scaled_img.jpg", scaled_img)
                    cv2.imshow("final output:", roi)
                return scaled_img

        else:
            y = int(points[0][0][1]) - int(qr_data[1])
            x = int(points[0][0][0]) - int(qr_data[4])
            print(" x and y")
            print(x)
            print(y)
            roi = image[
                y : y + height + int(qr_data[3]), x : x + width + int(qr_data[2])
            ]
            final_img = cv2.imwrite("finalized_image.jpg", roi)
            cv2.imshow("finalized image:", final_img)
            return final_img


if __name__ == "__main__":
    image_to_crop = decodeAndCrop("example_input_1.jpg")
    final_image = decodeAndCrop("scaled_img.jpg")
    cv2.imshow("Cropped:", image_to_crop)
    # cv2.imshow("Final: ", final_image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
_

上記のコードは、final_img = cv2.imwrite( "finalized_image.jpg"、ROI)Cv2.Error:OpenCV(4.2.0)/ユーザー/ travis/build/skvark/opencv-python/optcv/modules/imgcodecs /src/loadsave.cpp:715:エラー:(-215:アサーションに失敗しました)!_img.Empty()関数 'imwrite'


最新の更新の終わり:


QRコードの復号化された情報の例は、100,20,40,60,20、PXです。

ここで、この文書画像からQRコードを検出する必要があり、最初のステップでは、キャプチャされた画像に復号された情報に記載されているサイズのQRコードのサイズを比較する必要があります。 QR画像のサイズは90×90pxで、デコードされた情報からのサイズは100 x 100pxで、それを比較する必要があります。

次に、2番目のステップで、私はそれに応じて上位、右、下、左の変数を使用して完全な画像をトリミングする必要があります。上記の例によると、検出されたQRコードの位置から20pxの上、40px右、60px下、および20px右に画像をトリミングする必要があります。以下のイメージを追加しました。

私はQRコード情報を復号するためにしましたが、検出されたQRコード領域を保護イメージとして取り、それを言及したサイズでそれを比較してから、それに応じて画像をトリミングすることができますか。

これまでに試したことがあります。

_import cv2

image = cv2.imread('/Users/abdul/PycharmProjects/QScanner/images/second.jpg')

qrCodeDetector = cv2.QRCodeDetector()
decodedText, points, _ = qrCodeDetector.detectAndDecode(image)
qr_data = decodedText.split(',')
qr_size = qr_data[0]
top = qr_data[1]
right = qr_data[2]
bottom = qr_data[3]
left = qr_data[4]

print(f'Size: {qr_size}' + str(qr_data[5]))
print(f'Top: {top}')
print(f'Right: {right}')
print(f'Bottom: {bottom}')
print(f'Left: {left}')
if points is not None:
    pts = len(points)
    print(pts)
    for i in range(pts):
        nextPointIndex = (i+1) % pts
        cv2.line(image, Tuple(points[i][0]), Tuple(points[nextPointIndex][0]), (255,0,0), 5)
        print(points[i][0])
    print(decodedText)    
    cv2.imshow("Image", image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
else:
    print("QR code not detected")
_

イメージの例が次のとおりです。

enter image description here

そしてこれが入力イメージのサンプルです:

enter image description here

3
Abdul Rehman

ポイントを使用してwidthheightデータを手に入れ、_qr_data_サイズと比較してください。それから必要に応じてQRをトリミングしました。

_import cv2
import math  

image = cv2.imread('/ur/image/directory/qr.jpg')

qrCodeDetector = cv2.QRCodeDetector()
decodedText, points, _ = qrCodeDetector.detectAndDecode(image)
qr_data = decodedText.split(',')
qr_size = qr_data[0]
top = qr_data[1]
right = qr_data[2]
bottom = qr_data[3]
left = qr_data[4]

if points is not None:
    pts = len(points)
    print(pts)
    for i in range(pts):
        nextPointIndex = (i+1) % pts
        cv2.line(image, Tuple(points[i][0]), Tuple(points[nextPointIndex][0]), (255,0,0), 5)
        print(points[i][0])

    width = int(math.sqrt((points[0][0][0]-points[1][0][0])**2 + (points[0][0][1]-points[1][0][1])**2))
    height = int(math.sqrt((points[1][0][0]-points[2][0][0])**2 + (points[1][0][1]-points[2][0][1])**2))

    # Compare the size
    if(width==qr_data[0] and height==qr_data[0]):
        print("Sizes are equal")
    else:
        print("Width and height  " + str(width) + "x" +  str(height) + "  not equal to " 
        + str(qr_data[0]) + "x" + str(qr_data[0]))

    # Add the extension values to points and crop
    y = int(points[0][0][1]) - int(qr_data[1])
    x = int(points[0][0][0]) - int(qr_data[4])
    roi = image[y:y+height + int(qr_data[3]), x:x+width + int(qr_data[2])]
    print(decodedText)    
    cv2.imshow("Image", image)
    cv2.imshow("Crop", roi)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
else:
    print("QR code not detected")
_

結果:

enter image description here

0
Yunus Temurlenk

だから、あなたは主にここで3つの問題を抱えています。

  1. 画像が角度\ Thetaで回転されている場合
  2. シートが1つの平面である場合(すなわち、画像内では、上の行は線形ではないようではない。しかし、それは大したことにしてはいけません。)
  3. 黒い境界線あなたはいつもそれらを持っていますかそれとも違う背景になるかもしれませんか?これは重要です。それらをトリミングせずに、あなたは合理的な結果を得ることができないでしょう。

コードを少し改善し、境界線ピクセルを削除しました。

import cv2
import matplotlib.pyplot as plt    
import math
import numpy as np

image = cv2.imread('/Users/samettaspinar/Public/im.jpg')

qrCodeDetector = cv2.QRCodeDetector()
decodedText, points, _ = qrCodeDetector.detectAndDecode(image)
qr_data = decodedText.split(',')
qr_size = int(qr_data[0])
top = int(qr_data[1])
right = int(qr_data[2])
bottom = int(qr_data[3])
left = int(qr_data[4])

print(f'Size: {qr_size}' + str(qr_data[5]))
print(f'Top: {top}')
print(f'Right: {right}')
print(f'Bottom: {bottom}')
print(f'Left: {left}')

plt.imshow(image)
plt.show()

dists = [] #This is for estimating distances between corner points.
           #I will average them to find ratio of pixels in image vs qr_size  
           #in the optimal case, all dists should be equal

if points is not None:
    pts = len(points)
    for i in range(pts):
        p1 = points[i][0]
        p2 = points[(i+1) % pts][0]

        dists.append(math.sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2))

        print('line', Tuple(p1), Tuple(p2))
        image = cv2.line(image, Tuple(p1), Tuple(p2), (255,0,0), 5)
else:
    print("QR code not detected")

print('distances: ', dists)


# Remove the black border pixels. I had a simple idea for this
# Get the average intensity of the gray image
# If count the row average of the first half that are less than intensity/2. 
# It approx gives number of black borders on the left. etc.  
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
inten = np.mean(gray)

x = np.mean(gray, axis=0) # finds the vertical average
y = np.mean(gray, axis=1) # finds horizontal average

bl_left = np.sum([x[:int(col/2)] < inten/2])
bl_right = np.sum([x[int(col/2)+1:] < inten/2])

bl_top = np.sum([y[:int(row/2)] < inten/2])
bl_bottom = np.sum([y[int(row/2)+1:] < inten/2])

print('black margins: ', bl_left, bl_right, bl_top, bl_bottom)

# Estimate how many pixel you will crop out
ratio = np.mean(dists)/ int(qr_size)
print('actual px / qr_size in px: ', ratio)

row,col,dim = image.shape

top, left, right, bottom = int(top*ratio), int(left*ratio), int(right*ratio), int(bottom*ratio)
top += bl_top
left += bl_left
right += bl_right
bottom += bl_bottom

print('num pixels to be cropped: ', top, left, right, bottom)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image2 = image[top:row-bottom, left:col-right, :]

plt.imshow(image2)
plt.show()
 _

私は回転の問題を無視したことに注意してください。回転がある場合は、距離を計算した接線/ arctanを計算することによって角度を見つけることができます。

0
smttsp