Study: Artificial Intelligence(AI)/AI: 2D Vision(Det, Seg, Trac)

[CV] Glare Removal ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ •๋ฆฌ

DrawingProcess 2024. 5. 18. 17:04
๋ฐ˜์‘ํ˜•
๐Ÿ’ก ๋ณธ ๋ฌธ์„œ๋Š” 'Glare Removal ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ •๋ฆฌ'์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋†“์€ ๊ธ€์ž…๋‹ˆ๋‹ค.
๊ณผ๋„ํ•˜๊ณ  ์กฐ์ ˆ๋˜์ง€ ์•Š๋Š” ๋ฐ๊ธฐ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” Glareํ•œ ํ‘œ๋ฉด์€ ์˜์ƒ์—์„œ ์ œ๊ฑฐํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ๊ฐ€ ์ข…์ข…์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฐœ๋…๊ณผ ์ฝ”๋“œ ์ˆ˜์ค€์œผ๋กœ ์ž์„ธํžˆ ์ •๋ฆฌํ•˜์˜€์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

1. Glare Removal

Glare?

Glare๋Š” ๊ณผ๋„ํ•˜๊ณ  ์กฐ์ ˆ๋˜์ง€ ์•Š๋Š” ๋ฐ๊ธฐ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ์‹œ๊ฐ์  ๊ฐ๊ฐ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์ฃผ๊ด€์ ์ด๊ณ  ๋ˆˆ๋ถ€์‹ฌ์— ๋Œ€ํ•œ ๋ฏผ๊ฐ์„ฑ์€ ๋งค์šฐ ๋‹ค์–‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋…ธ์ธ๋“ค์€ ๋ณดํ†ต ๋ˆˆ์˜ ๋…ธํ™”๋œ ํŠน์„ฑ ๋•Œ๋ฌธ์— ๋ˆˆ๋ถ€์‹ฌ์— ๋” ๋ฏผ๊ฐํ•ฉ๋‹ˆ๋‹ค.

Glare Detection

1) Threshold based

์ผ๋ฐ˜์ ์œผ๋กœ Glare๊ฐ€ ์กด์žฌํ•  ๋•Œ ํ”ฝ์…€ ๊ฐ’์ด 180๋ณด๋‹ค ๋†’๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๋Š” ์ „์—ญ ์ด์ง„ํ™”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‰ฝ๊ฒŒ ์‹๋ณ„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

def create_mask(image):
    gray = cv2.cvtColor( image, cv2.COLOR_BGR2GRAY )
    blurred = cv2.GaussianBlur( gray, (9,9), 0 )
    _,thresh_img = cv2.threshold( blurred, 180, 255, cv2.THRESH_BINARY)
    thresh_img = cv2.erode( thresh_img, None, iterations=2 )
    thresh_img  = cv2.dilate( thresh_img, None, iterations=4 )
    # perform a connected component analysis on the thresholded image,
    # then initialize a mask to store only the "large" components
    # labels = measure.label( thresh_img, neighbors=8, background=0 )
    labels = measure.label( thresh_img, connectivity=2, background=0 )
    mask = np.zeros( thresh_img.shape, dtype="uint8" )
    # loop over the unique components
    for label in np.unique( labels ):
        # if this is the background label, ignore it
        if label == 0:
            continue
        # otherwise, construct the label mask and count the
        # number of pixels
        labelMask = np.zeros( thresh_img.shape, dtype="uint8" )
        labelMask[labels == label] = 255
        numPixels = cv2.countNonZero( labelMask )
        # if the number of pixels in the component is sufficiently
        # large, then add it to our mask of "large blobs"
        if numPixels > 300:
            mask = cv2.add( mask, labelMask )
    return mask
  1. ์ด๋ฏธ์ง€๋ฅผ ๊ทธ๋ ˆ์ด์Šค์ผ€์ผ๋กœ ๋ณ€ํ™˜
  2. ๊ฐ€์šฐ์‹œ์•ˆ ํ–‰๋ ฌ(9x9)์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€๋ฅผ ๋ธ”๋Ÿฌ๋งํ•˜์—ฌ ๋…ธ์ด์ฆˆ ๊ฐ์†Œ
  3. ๊ธ€๋กœ๋ฒŒ ์ž„๊ณ„๊ฐ’ ๋ฐฉ๋ฒ•์—์„œ ์ž„๊ณ„๊ฐ’์„ 180์œผ๋กœ ์„ค์ • -> ํ”ฝ์…€ ๊ฐ’์ด 180 ์ด์ƒ์ด๋ฉด, ํฐ์ƒ‰
  4. small blobs of noise ์ œ๊ฑฐํ•˜๊ณ ์ž ๋ชจํด๋กœ์ง€ ํŒฝ์ฐฝ, ์นจ์‹ ์—ฐ์‚ฐ(erosion, dilations) ์ˆ˜ํ–‰
  5. Connected Component Labeling: sikit-image ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‚ด image.measure.labels
  6. ๋งˆ์Šคํฌ(Mask) ์ƒ์„ฑ: numPixel์ด ๋ฏธ๋ฆฌ ์ •์˜๋œ ์ž„๊ณ„๊ฐ’(์ด ๊ฒฝ์šฐ, 300 ํ”ฝ์…€)์„ ์ดˆ๊ณผํ•˜๋ฉด blob์„ "์ถฉ๋ถ„ํžˆ ํฌ๋‹ค"๊ณ  ๊ฐ„์ฃผํ•˜์—ฌ ๋งˆ์Šคํฌ๋กœ ์ง€์ •

Threshold based Result

Glare Removal Algorithms: Inpainting method

Image Inpainting์€ ์ด๋ฏธ์ง€์—์„œ ๋ˆ„๋ฝ๋œ ์˜์—ญ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ์ž‘์—…์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์ปดํ“จํ„ฐ ๋น„์ „์—์„œ ์ค‘์š”ํ•œ ๋ฌธ์ œ์ด๋ฉฐ ๊ฐ์ฒด ์ œ๊ฑฐ, ์ด๋ฏธ์ง€ ๋ณต์›, ์กฐ์ž‘, ์žฌํ‘œ์ , ํ•ฉ์„ฑ ๋ฐ ์ด๋ฏธ์ง€ ๊ธฐ๋ฐ˜ ๋ Œ๋”๋ง๊ณผ ๊ฐ™์€ ๋งŽ์€ ์ด๋ฏธ์ง• ๋ฐ ๊ทธ๋ž˜ํ”ฝ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ•„์ˆ˜์ ์ธ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

1) OpenCV: Naiver-Stokes method, Fast Marching method

OpenCV์—์„œ๋Š” Naiver-Stokes method(NS), Fast Marching method(Telea) ๋ฐฉ์‹์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ํ•ด๋‹น Method์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์„ค๋ช…ํ•ด๋‘๊ธด ํ•˜์˜€์œผ๋‚˜, CPU ์—ฐ์‚ฐ์ด๋ผ ๊ทธ๋Ÿฐ์ง€ ๋งค์šฐ ๋Š๋ฆฌ๋ฉฐ ๊ทธ๋ฆฌ ์ถ”์ฒœํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

Naiver-Stokes method

Image intensities of the region can be updated using the partial differential equation, and the smoothness of the image can be calculated by the image Laplacian (The Laplacian is a 2-D isotropic measure of the 2nd spatial derivative of an image. The Laplacian of an image highlights regions of rapid intensity change and is therefore often used for edge detection (see zero-crossing edge detectors). The Laplacian is often applied to an image that has first been smoothed with something approximating a Gaussian smoothing filter in order to reduce its sensitivity to noise, and hence the two variants will be described together here. The operator normally takes a single gray-level image as input and produces another gray-level image as output)

Laplacian and partial differential equations can be used to preserve the edges and continue to propagate colour information in smooth regions. This is one of the methods to do image inpainting.

Fast Marching method

a weighted average over a known image neighbourhood of the pixel is used for image smoothness to inpaint. The known neighbourhood pixels and gradients are used to estimate the colour of the pixel to be inpainted.

We can use any of the above algorithms to inpaint.

How to use in OpenCV python

dst = cv2.inpaint(src, inpaintMask, inpaintRadius, flags)
  • src → The input glared image
  • dst → Output image
  • inpaintMask →A binary mask indicating pixels to be inpainted.
  • inpaintRadius →Neighborhood around a pixel to inpaint.
  • flags → INPAINT_NS,(Navier-Stokes based method) or INPAINT_TELEA (Fast marching based method)

์˜ˆ์ œ ๋ฐ ํ™œ์šฉ

result1 = cv2.inpaint(img, mask, 101, cv2.INPAINT_TELEA)

When we select the inpaintRadius, if the regions to be inpainted are thin, smaller values produce better results (less blurry).

OpenCV Result: Naiver-Stokes method, Fast Marching method

2) Inpainting SOTA: e.g. co-mod-gan

SOTA ๋…ผ๋ฌธ ๋ฐ ์ฝ”๋“œ๋Š” ๋Œ€์ฒด๋กœ paperwithcode์—์„œ ์ฐพ์•„๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. Image Inpainting ๋ถ„์•ผ์˜ outdoor ํ™˜๊ฒฝ์—์„œ์˜ benchmark์—๋Š” Place2๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™๊ณ  ์ด ์ค‘ ์œ ๋ช…ํ•œ๋ฐ ์ฝ”๋“œ๊ฐ€ ์ž˜ ๋Œ์•„๊ฐ€๋Š” ๊ฒƒ์„ ๊ธฐ์ค€์œผ๋กœ ํ…Œ์ŠคํŠธ ๋…ผ๋ฌธ(co-mod-gan)์„ ์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ƒ๋‹นํžˆ ๋น ๋ฅธ ์†๋„๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, ๋Œ€์ฒด๋กœ Inpainting ๋ถ„์•ผ๋Š” 512 x 512 ์‚ฌ์ด์ฆˆ๋ฅผ ์ตœ๋Œ€๋กœ ์ง€์›ํ•˜๊ธฐ์— ์ด๋ฏธ์ง€๋ฅผ ํฌ๋กญํ•˜์—ฌ ์ธํ’‹์œผ๋กœ ๋„ฃ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.

Inpainting SOTA Result: e.g. co-mod-gan

์ฐธ๊ณ 

๋ฐ˜์‘ํ˜•