Perbaikan Skew gambar untuk Akurasi Mesin Scanner

By | January 14, 2021
Print Friendly, PDF & Email
1,994 Views

Cerita ini dimulai ketikan penulis menggunakan aplikasi scanner gratisan yang saat ini banyak digunakan untuk platform android yaitu CamScanner, dengan beberapa fitur dasar seperti detect skewing. Dasar operasi ini yaitu transalasi dan affine. Bila sedang menangani sebuah project yang berkenaan dengan scanner document maka pastikan algoritma ini ada dalam core engine kalian. Hal menarik adalah kita hanya menggunakan 3 package/library yaitu opencv, imutils, serta scikit-image. Yuk kita bahas satu-persatu saja

Skewing

Skewing bisa terjadi ketika posisi capture tidak segaris dengan object sehingga yang terjadi bisa saja seperti ini

Bila aplikasinya bisa deteksi skew dan melakukan deskewing maka hal ini akan semakin menarik karena aplikasi yang kita buat menjadi lebih pintar. Kalian bisa melihat yang semula object berbentuk rectangle menjadi sebuah prism

Find Contour

Dasar algoritma ini bekerja dengan operasi find Contour sering disebut dengan blob operation (kalau kalian menggunakan Matlab) yang bertujuan diantaranya

  1. menemukan objek,
  2. letak koordinat,
  3. convex hull,
  4. size

kalian bisa baca link berikut agar paham (harap harus dibedakan mengenai retrieval mode nya ya karena sangat berpengaruh jika didalam objek tersebut ada objek lagi/inner object)

  1. https://softscients.com/2020/03/30/buku-pengolahan-citra-digital-dengan-python-dan-opencv-contour-retrieval-mode-find-contour/
  2. https://softscients.com/2020/03/30/buku-pengolahan-citra-digital-dengan-python-dan-opencv-merging-binary-object/

Find Contour bekerja pada image binary sehingga kalian harus memastikan bahwa operasi segmentasi dapat bekerja dengan baik, nah agar fokus ke pembahasan ini, kita gunakan sebuah image yang clear/bebas dari noise dengan 1 objek.

Dengan hasil informasi mengenai posisi A (x,y) dan B (x+width, y+height) seperti berikut:

import numpy as np
import cv2
from matplotlib import pyplot as plt

font = cv2.FONT_HERSHEY_SIMPLEX
url = 'gambar.jpg'
image = cv2.imread(url,1)
image2 = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edged = cv2.Canny(gray, 10, 50)
cnts,hierarcy = cv2.findContours(edged.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for cnt in cnts:
    [x,y,w,h] = cv2.boundingRect(cnt)      
    if w > 10 and h>10:
        cv2.rectangle(image2,(x,y),(x+w,y+h),(255,255,0),2)
        cv2.putText(image2,'A',(y,x), font,1,(255,255,255),2)
        cv2.putText(image2,'B',(y+w,x+h), font,1,(255,255,255),2)
        
plt.close('all')
plt.imshow(image2,cmap='gray')
plt.show()

Nah seharusnya kita mendeteksi ke 4 corner sebagai berikut

Untuk mendapatkan tiap corner diatas, opencv sudah dilengkapi dengan perintah arcLength() dan approxPlotyDP() sebagai berikut

peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)

Lebih lengkapnya

letak=['A','B','C','D']
screenCnt = None
for cnt in cnts:
    peri = cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
    if len(approx) == 4:
        screenCnt = approx
        index = 0
        for app in approx:
            #print(app)
            x = app[0][0]
            y = app[0][1]
            cv2.putText(image2,letak[index],(x,y), font,1,(255,0,0),2)
            index = index+1
        break        

cv2.drawContours(image2, [screenCnt], -1, (0, 255, 0), 2)
plt.close('all')
plt.imshow(image2,cmap='gray')
plt.show()

Contoh gambar yang lainnya yaitu untuk menentukan corner image

Perbaikan Skew gambar untuk Akurasi Mesin Scanner

Setelah didapatkan titik A, B, C, dan D maka akan dihitung dan dilakukan affine

Algoritma ini kami temukan di pyimagesearch.com, nah kalian bisa menggunakan kode dibawah ini

import numpy as np
import cv2
import imutils
from skimage import exposure
from matplotlib import pyplot as plt



image = cv2.imread('gambar 7.jpg')

font = cv2.FONT_HERSHEY_SIMPLEX
pembagi = 1000

ratio = image.shape[0] / pembagi
orig = image.copy()
image = imutils.resize(image, height = pembagi)
image2 = image.copy()
# convert the image to grayscale, blur it, and find edges
# in the image
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
edged = cv2.Canny(gray, 30, 200)



cnts,hierarcy = cv2.findContours(edged.copy(),cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)


#untuk menggambar sebuah posisi masing-masing sudut
letak=['A','B','C','D']
screenCnt = None
for cnt in cnts:
    peri = cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, 0.015 * peri, True)
    #approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
    if len(approx) == 4: #pastikan bahwa sudut tersebut punya 4 sudut
        screenCnt = approx
        index = 0
        for app in approx:
            #print(app)
            x = app[0][0]
            y = app[0][1]
            cv2.putText(image2,letak[index],(x,y), font,1,(255,0,0),2)
            index = index+1
        break        

cv2.drawContours(image2, [screenCnt], -1, (0, 255, 0), 2)
plt.close('all')
plt.figure(),plt.imshow(image2,cmap='gray'), plt.show()



# now that we have our screen contour, we need to determine
# the top-left, top-right, bottom-right, and bottom-left
# points so that we can later warp the image -- we'll start
# by reshaping our contour to be our finals and initializing
# our output rectangle in top-left, top-right, bottom-right,
# and bottom-left order
pts = screenCnt.reshape(4, 2)
rect = np.zeros((4, 2), dtype = "float32")

# the top-left point has the smallest sum whereas the
# bottom-right has the largest sum
s = pts.sum(axis = 1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]

# compute the difference between the points -- the top-right
# will have the minumum difference and the bottom-left will
# have the maximum difference
diff = np.diff(pts, axis = 1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]

# multiply the rectangle by the original ratio
rect *= ratio

# now that we have our rectangle of points, let's compute
# the width of our new image
(tl, tr, br, bl) = rect
widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))

# ...and now for the height of our new image
heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))

# take the maximum of the width and height values to reach
# our final dimensions
maxWidth = max(int(widthA), int(widthB))
maxHeight = max(int(heightA), int(heightB))

# construct our destination points which will be used to
# map the screen to a top-down, "birds eye" view
dst = np.array([
   [0, 0],
   [maxWidth - 1, 0],
   [maxWidth - 1, maxHeight - 1],
   [0, maxHeight - 1]], dtype = "float32")

# calculate the perspective transform matrix and warp
# the perspective to grab the screen
M = cv2.getPerspectiveTransform(rect, dst)
warp = cv2.warpPerspective(orig, M, (maxWidth, maxHeight))

# convert the warped image to grayscale and then adjust
# the intensity of the pixels to have minimum and maximum
# values of 0 and 255, respectively
warp = cv2.cvtColor(warp, cv2.COLOR_BGR2GRAY)
warp = exposure.rescale_intensity(warp, out_range = (0, 255))

   
plt.figure()
plt.subplot(1,2,1),plt.imshow(image2,cmap='gray')
plt.subplot(1,2,2),plt.imshow(warp,cmap='gray'), plt.show()

 

Leave a Reply