ฉันจะทำให้ภาพคมชัดขึ้นใน OpenCV ได้อย่างไร


122

ฉันจะทำให้ภาพคมชัดขึ้นโดยใช้OpenCV ได้อย่างไร

มีหลายวิธีในการทำให้เรียบหรือเบลอ แต่ไม่มีเลยที่ฉันจะเห็นการเหลา

คำตอบ:


160

มีขั้นตอนทั่วไปอย่างหนึ่งในบทความ Wikipedia เกี่ยวกับการกำบังที่ไม่คมชัด :

คุณใช้ตัวกรองการปรับให้เรียบแบบเกาส์เซียนและลบเวอร์ชันที่ปรับให้เรียบออกจากรูปภาพต้นฉบับ (ด้วยวิธีการถ่วงน้ำหนักเพื่อให้ค่าของพื้นที่คงที่คงที่)

ที่จะได้รับรุ่นรุนแรงขึ้นของการframeเข้าสู่image: (ทั้งcv::Mat)

cv::GaussianBlur(frame, image, cv::Size(0, 0), 3);
cv::addWeighted(frame, 1.5, image, -0.5, 0, image);

พารามิเตอร์มีบางอย่างที่คุณต้องปรับด้วยตัวคุณเอง

นอกจากนี้ยังมีการเหลา Laplacian คุณควรหาอะไรบางอย่างเมื่อคุณใช้ Google


1
มีวิธีในการจำลองผล Unsharp Mask ของ Photoshop หรือไม่?
Royi

@Drazick คุณถามเพราะไม่สามารถจำลองได้หรือไม่? ลิงก์ไปยังวิกิพีเดียได้รับด้านบน digital_unsharp_maskingจะเฉพาะเจาะจง
tilaprimera

@tilaprimera ฉันถามเพราะ USM ของ Photoshop แตกต่างจาก USM แบบ "คลาสสิก"
Royi

50

คุณสามารถลองใช้เคอร์เนลธรรมดาและฟังก์ชันfilter2Dเช่นใน Python:

kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])
im = cv2.filter2D(im, -1, kernel)

Wikipedia มีภาพรวมที่ดีของเมล็ดพร้อมตัวอย่างเพิ่มเติมที่นี่ - https://en.wikipedia.org/wiki/Kernel_(image_processing)

ในการประมวลผลภาพเคอร์เนลเมทริกซ์คอนโวลูชั่นหรือมาสก์เป็นเมทริกซ์ขนาดเล็ก ใช้สำหรับการเบลอการเหลาการทำให้นูนการตรวจจับขอบและอื่น ๆ สิ่งนี้ทำได้โดยทำการ Convolution ระหว่างเคอร์เนลและรูปภาพ


14

คุณสามารถค้นหาโค้ดตัวอย่างเกี่ยวกับความคมชัดของภาพโดยใช้ "หน้ากากไม่ชัด" อัลกอริทึมที่OpenCV เอกสาร

การเปลี่ยนค่านิยมของsigma, threshold, amountจะให้ผลลัพธ์ที่แตกต่างกัน

// sharpen image using "unsharp mask" algorithm
Mat blurred; double sigma = 1, threshold = 5, amount = 1;
GaussianBlur(img, blurred, Size(), sigma, sigma);
Mat lowContrastMask = abs(img - blurred) < threshold;
Mat sharpened = img*(1+amount) + blurred*(-amount);
img.copyTo(sharpened, lowContrastMask);

สวยขนาดนี้!
roosevelt

12

คุณสามารถทำให้ภาพคมชัดขึ้นโดยใช้มาสก์ที่ไม่คมชัด คุณสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับการกำบังไม่ชัดนี่ และนี่คือการใช้งาน Python โดยใช้ OpenCV:

import cv2 as cv
import numpy as np

def unsharp_mask(image, kernel_size=(5, 5), sigma=1.0, amount=1.0, threshold=0):
    """Return a sharpened version of the image, using an unsharp mask."""
    blurred = cv.GaussianBlur(image, kernel_size, sigma)
    sharpened = float(amount + 1) * image - float(amount) * blurred
    sharpened = np.maximum(sharpened, np.zeros(sharpened.shape))
    sharpened = np.minimum(sharpened, 255 * np.ones(sharpened.shape))
    sharpened = sharpened.round().astype(np.uint8)
    if threshold > 0:
        low_contrast_mask = np.absolute(image - blurred) < threshold
        np.copyto(sharpened, image, where=low_contrast_mask)
    return sharpened

def example():
    image = cv.imread('my-image.jpg')
    sharpened_image = unsharp_mask(image)
    cv.imwrite('my-sharpened-image.jpg', sharpened_image)

ดูเหมือนว่าจะเป็นรุ่นที่มีประโยชน์ทีเดียว คุณช่วยกรุณาเพิ่มข้อมูลเพิ่มเติมเล็กน้อยเกี่ยวกับพารามิเตอร์ ขนาดเคอร์เนลและซิกม่าสามารถค้นหาได้ใน opencv แต่จำนวนและเกณฑ์ล่ะ ขอบคุณ!
choise

2
@choise amountเป็นเพียงปริมาณของการเหลา ตัวอย่างเช่นamount2.0 จะให้ภาพที่คมชัดกว่าเมื่อเทียบกับค่าเริ่มต้นคือ 1.0 thresholdเป็นเกณฑ์สำหรับมาสก์คอนทราสต์ต่ำ กล่าวอีกนัยหนึ่งพิกเซลที่ความแตกต่างระหว่างอินพุตและภาพเบลอน้อยกว่าthresholdจะยังคงไม่เปลี่ยนแปลง
Soroush

11

Any Image คือการรวบรวมสัญญาณของความถี่ต่างๆ ความถี่ที่สูงขึ้นจะควบคุมขอบและความถี่ต่ำจะควบคุมเนื้อหาของภาพ ขอบจะเกิดขึ้นเมื่อมีการเปลี่ยนแปลงอย่างรวดเร็วจากค่าพิกเซลหนึ่งไปเป็นค่าพิกเซลอื่นเช่น 0 และ 255 ในเซลล์ที่อยู่ติดกัน เห็นได้ชัดว่ามีการเปลี่ยนแปลงที่คมชัดและด้วยเหตุนี้ขอบและความถี่สูง สำหรับการเพิ่มความคมชัดของภาพการเปลี่ยนภาพเหล่านี้สามารถปรับปรุงเพิ่มเติมได้

วิธีหนึ่งคือการแปลงเคอร์เนลตัวกรองที่สร้างขึ้นเองกับรูปภาพ

    import cv2
    import numpy as np

    image = cv2.imread('images/input.jpg')
    kernel = np.array([[-1,-1,-1], 
                       [-1, 9,-1],
                       [-1,-1,-1]])
    sharpened = cv2.filter2D(image, -1, kernel) # applying the sharpening kernel to the input image & displaying it.
    cv2.imshow('Image Sharpening', sharpened)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

มีอีกวิธีหนึ่งในการลบภาพเบลอออกจากเวอร์ชันสว่าง ซึ่งจะช่วยให้ภาพคมชัดขึ้น แต่ควรทำด้วยความระมัดระวังเนื่องจากเราเพิ่งเพิ่มค่าพิกเซล ลองนึกภาพค่าพิกเซลสีเทา 190 ซึ่งหากคูณด้วย 2 น้ำหนักจะเท่ากับ 380 แต่ถูกตัดออกที่ 255 เนื่องจากช่วงพิกเซลสูงสุดที่อนุญาต นี่คือการสูญเสียข้อมูลและนำไปสู่การล้างภาพออก

    addWeighted(frame, 1.5, image, -0.5, 0, image);

5

เพื่อความชัดเจนในหัวข้อนี้ควรทำบางประเด็น:

  1. การทำให้ภาพคมชัดเป็นปัญหาที่ไม่เหมาะสม กล่าวอีกนัยหนึ่งการเบลอเป็นการดำเนินการที่สูญเสียและโดยทั่วไปแล้วจะไม่สามารถทำได้

  2. ในการเพิ่มความคมชัดของภาพเดียวคุณต้องเพิ่มข้อ จำกัด (สมมติฐาน) ว่าคุณต้องการภาพประเภทใดและภาพนั้นเบลออย่างไร นี่คือพื้นที่ของสถิติภาพธรรมชาติ วิธีการลับคมจะเก็บสถิติเหล่านี้ไว้อย่างชัดเจนหรือโดยปริยายในอัลกอริทึมของพวกเขา (การเรียนรู้เชิงลึกเป็นการเข้ารหัสโดยปริยายที่สุด) วิธีการทั่วไปในการเพิ่มน้ำหนักบางระดับของการสลายตัวของพีระมิด DOG หรือ Laplacianซึ่งเป็นคำตอบทั่วไปของ Brian Burns ถือว่าการเบลอภาพแบบเกาส์ทำให้ภาพเสียหายและวิธีการถ่วงน้ำหนักนั้นเชื่อมโยงกับสมมติฐานเกี่ยวกับสิ่งที่เป็นอยู่ ในภาพเริ่มต้นด้วย

  3. แหล่งข้อมูลอื่น ๆ อาจทำให้ปัญหามีความคมชัดขึ้น แหล่งข้อมูลทั่วไปเช่นวิดีโอของวัตถุที่กำลังเคลื่อนที่หรือการตั้งค่าหลายมุมมอง การเพิ่มความคมชัดในการตั้งค่านั้นมักเรียกว่าsuper-resolution (ซึ่งเป็นชื่อที่ไม่ดีสำหรับมัน แต่มันติดอยู่ในวงวิชาการ) มีวิธีการที่มีความละเอียดสูงใน OpenCVมานานแล้ว .... แม้ว่าโดยปกติแล้วพวกเขาจะไม่ได้ผลดีสำหรับปัญหาจริงในที่สุดฉันก็ลองดู ฉันคาดหวังว่าการเรียนรู้เชิงลึกจะให้ผลลัพธ์ที่ยอดเยี่ยมที่นี่เช่นกัน อาจจะมีคนโพสต์ในข้อคิดเห็นเกี่ยวกับสิ่งที่คุ้มค่า


3

ในการทำให้ภาพคมชัดขึ้นเราสามารถใช้ฟิลเตอร์ (เช่นเดียวกับคำตอบก่อนหน้านี้)

kernel = np.array([[-1, -1, -1],[-1, 8, -1],[-1, -1, 0]], np.float32) 

kernel /= denominator * kernel

จะมากที่สุดเมื่อตัวส่วนเป็น 1 และจะลดลงเมื่อเพิ่มขึ้น (2.3 .. )

ตัวที่ใช้มากที่สุดคือเมื่อตัวส่วนเป็น 3

ด้านล่างนี้คือการนำไปใช้งาน

kernel = np.array([[-1, -1, -1],[-1, 8, -1],[-1, -1, 0]], np.float32) 

kernel = 1/3 * kernel

dst = cv2.filter2D(image, -1, kernel)

บางสิ่งบางอย่างที่ดูเหมือนว่าจะหายไปใกล้"มันจะมากที่สุด"
Peter Mortensen

ใช่ปีเตอร์ขอบคุณ!
kaustubhd9

-4

ลองใช้สิ่งนี้:

cv::bilateralFilter(img, 9, 75, 75);

คุณอาจจะหาข้อมูลเพิ่มเติมได้ที่นี่


9
คำถามคือเกี่ยวกับการเพิ่มความคมชัดของภาพไม่ใช่การรักษาขอบให้เรียบ
Michael Burdinov
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.