Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

Đối với Python, tôi chưa tìm thấy chức năng OpenCV cung cấp độ tương phản. Như những người khác đã đề xuất, có một số kỹ thuật để tự động tăng độ tương phản bằng cách sử dụng một công thức rất đơn giản.

Trong các tài liệu OpenCV chính thức, có ý kiến ​​cho rằng phương trình này có thể được sử dụng để áp dụng cả độ tương phản và độ sáng cùng một lúc:

new_img = alpha*old_img + beta

trong đó alpha tương ứng với độ tương phản và beta là độ sáng. Trường hợp khác nhau

alpha 1  beta 0      --> no change  
0 < alpha < 1        --> lower contrast  
alpha > 1            --> higher contrast  
-127 < beta < +127   --> good range for brightness values

Trong C/C ++, bạn có thể thực hiện phương trình này bằng CV :: MAT :: Convertto, nhưng chúng tôi không có quyền truy cập vào phần đó của thư viện từ Python. Để thực hiện nó trong Python, tôi khuyên bạn nên sử dụng chức năng CV :: AddWights, bởi vì nó nhanh chóng và nó tự động buộc đầu ra phải nằm trong phạm vi 0 đến 255 (ví dụ: với hình ảnh màu 24 bit, 8 bit mỗi kênh). Bạn cũng có thể sử dụng

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
5 như đề xuất của @Nathancy.

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted

Công thức và mã trên nhanh chóng để viết và sẽ thay đổi độ sáng và độ tương phản. Nhưng chúng mang lại kết quả khác biệt đáng kể so với các chương trình chỉnh sửa ảnh. Phần còn lại của câu trả lời này sẽ mang lại kết quả sẽ tái tạo hành vi trong GIMP và độ sáng và độ tương phản của libreoffice. Đó là nhiều dòng mã hơn, nhưng nó cho kết quả tốt đẹp.

Tương phản

Trong GIMP, mức độ tương phản đi từ -127 đến +127. Tôi đã điều chỉnh các công thức từ đây để phù hợp với phạm vi đó.

f = 131*(tương phản + 127)/(127*(131-đối độ)) new_image = f*(old_image-127) + 127 = f*(old_image) + 127*(1-f)
new_image = f*(old_image - 127) + 127 = f*(old_image) + 127*(1-f)

Để tìm ra độ sáng, tôi đã tìm ra mối quan hệ giữa độ sáng và mức độ và thông tin được sử dụng trong bài đăng cấp này để đi đến một giải pháp.

#pseudo code
if brightness > 0
    shadow = brightness
    highlight = 255
else:
    shadow = 0
    highlight = 255 + brightness
new_img = ((highlight - shadow)/255)*old_img + shadow

độ sáng và độ tương phản trong python và opencv

Đặt tất cả lại với nhau và thêm bằng cách sử dụng hình ảnh "Mandrill" tham chiếu từ USC SIPI:

import cv2
import numpy as np

# Open a typical 24 bit color image. For this kind of image there are
# 8 bits (0 to 255) per color channel
img = cv2.imread('mandrill.png')  # mandrill reference image from USC SIPI

s = 128
img = cv2.resize(img, (s,s), 0, 0, cv2.INTER_AREA)

def apply_brightness_contrast(input_img, brightness = 0, contrast = 0):
    
    if brightness != 0:
        if brightness > 0:
            shadow = brightness
            highlight = 255
        else:
            shadow = 0
            highlight = 255 + brightness
        alpha_b = (highlight - shadow)/255
        gamma_b = shadow
        
        buf = cv2.addWeighted(input_img, alpha_b, input_img, 0, gamma_b)
    else:
        buf = input_img.copy()
    
    if contrast != 0:
        f = 131*(contrast + 127)/(127*(131-contrast))
        alpha_c = f
        gamma_c = 127*(1-f)
        
        buf = cv2.addWeighted(buf, alpha_c, buf, 0, gamma_c)

    return buf


font = cv2.FONT_HERSHEY_SIMPLEX
fcolor = (0,0,0)

blist = [0, -127, 127,   0,  0, 64] # list of brightness values
clist = [0,    0,   0, -64, 64, 64] # list of contrast values


out = np.zeros((s*2, s*3, 3), dtype = np.uint8)

for i, b in enumerate(blist):
    c = clist[i]
    print('b, c:  ', b,', ',c)
    row = s*int(i/3)
    col = s*(i%3)
    
    print('row, col:   ', row, ', ', col)
    
    out[row:row+s, col:col+s] = apply_brightness_contrast(img, b, c)
    msg = 'b %d' % b
    cv2.putText(out,msg,(col,row+s-22), font, .7, fcolor,1,cv2.LINE_AA)
    msg = 'c %d' % c
    cv2.putText(out,msg,(col,row+s-4), font, .7, fcolor,1,cv2.LINE_AA)
    
    cv2.putText(out, 'OpenCV',(260,30), font, 1.0, fcolor,2,cv2.LINE_AA)

cv2.imwrite('out.png', out)

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

Tôi đã xử lý thủ công các hình ảnh trong GIMP và thêm các thẻ văn bản trong Python/OpenCV:

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

Lưu ý: @utkarshbhardwaj đã đề xuất rằng người dùng Python 2.x phải chuyển mã tính toán hiệu chỉnh tương phản vào phao để nhận kết quả nổi, như vậy: @UtkarshBhardwaj has suggested that Python 2.x users must cast the contrast correction calculation code into float for getting floating result, like so:

...
if contrast != 0:
        f = float(131*(contrast + 127))/(127*(131-contrast))
...

  • Một chút căn bản về ảnh kỹ thuật số (digital image)
  • Xử lý hình ảnh bằng Pillow và OpenCV
    • 1. Chuyển ảnh màu sang grayscale
      • 1.1 Code thủ công
      • 1.2 Sử dụng Pillow
    • 2. Thay đổi độ tương phản (contrast)
    • 3. Thay đổi độ sáng (brightness)
    • 4. Làm mờ (Gaussian blur)
    • 5. Làm tối 4 góc (vignette) sử dụng OpenCV và numpy
  • Cơm thêm
    • Tìm các cạnh bằng phương pháp Canny (Canny edge detection)
    • Vẽ countour của ảnh
    • Nhận diện gương mặt bằng OpenCV

Một chút căn bản về ảnh kỹ thuật số (digital image)

Một hình ảnh (kỹ thuật số) được tạo thành bởi nhiều phần tử gọi là pixel (hay điểm ảnh). Thường thì một hình được biểu diễn bằng một mảng hai chiều gồm nhiều pixels. Mỗi pixel (cụ thể là hình RGB) mang trong mình 3 thông số màu: Red, Green, Blue.Red, Green, Blue.

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

Ngoài ra, đối với không gian RGBA thì nó có một kênh thứ 4 là Alpha, trong đó Alpha là một thông số chỉ độ trong suốt của pixel đó.Alpha, trong đó Alpha là một thông số chỉ độ trong suốt của pixel đó.

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

Như đã nói ở trên, một pixel mang 3 giá trị màu, vì trên thực tế mỗi pixel được cấu thành bao gồm 3 sub-pixels. Và pixel cũng không có kích thước vật lý cụ thể, mà nó phụ thuộc vào pixel density. Mỗi pixel chứa được 256 (0-255) giá trị, cho nên về mặt lý thuyết 3 sub-pixels hiện thị được 256^3 = 16777216 (~16 triệu màu). Nhưng tất nhiên là mắt người chưa hẳn đã phân biệt được 16 triệu màu này.kích thước vật lý cụ thể, mà nó phụ thuộc vào pixel density. Mỗi pixel chứa được 256 (0-255) giá trị, cho nên về mặt lý thuyết 3 sub-pixels hiện thị được 256^3 = 16777216 (~16 triệu màu). Nhưng tất nhiên là mắt người chưa hẳn đã phân biệt được 16 triệu màu này.

Xử lý hình ảnh bằng Pillow và OpenCV

Trong toàn bài này mình sẽ sử dụng ảnh này làm ảnh gốc để chỉnh sửa. Phần code có hơi mì ăn liền cho nên bạn nào khó tính vui lòng bỏ qua.

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

1. Chuyển ảnh màu sang grayscale

Về cơ bản thì grayscale (hình trắng đen) là loại ảnh mà tất cả pixels chỉ mang thông tin về độ sáng, hay nói cách khác chỉ thể hiện các sắc thái của màu xám (Luminance mode). Trong không gian màu RGB, thì màu xám là màu mà các sắc tố Red, Green, Blue có giá trị bằng nhau. Ví dụ màu đỏ là

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
6 thì nếu ta muốn chuyển nó sang xám thì lấy giá trị trung bình của 3 sub-pixels và tạo thành 1 pixel mới
import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
7Red, Green, Blue có giá trị bằng nhau. Ví dụ màu đỏ là
import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
6 thì nếu ta muốn chuyển nó sang xám thì lấy giá trị trung bình của 3 sub-pixels và tạo thành 1 pixel mới
import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
7

1.1 Code thủ công

Đầu tiên chúng ta áp dụng lý thuyết ở trên để sửa từng pixel cho ảnh gốc để tạo ra ảnh mới:

from PIL import Image
img = Image.open('rick-morty.png')
pixels = img.load()

new_img = Image.new(img.mode, img.size)
pixels_new = new_img.load()
for i in range(new_img.size[0]):
    for j in range(new_img.size[1]):
        r, b, g = pixels[i,j]
        avg = int(round((r + b + g) / 3))
        pixels_new[i,j] = (avg, avg, avg, 0)
new_img.show()

Chúng ta có ảnh gốc được chuyển thành grayscale như sau:

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

1.2 Sử dụng Pillow

Pillow là một bản fork của PIL (Python Image Library) một thư viện xử lý hình ảnh của Python. Do PIL được phát hành từ 2009 và không có cập nhật thường xuyên, cho nên PIL đã bị thay thế bở Pillow trên các bản phân phối của Debian và Ubuntu luôn.

from PIL import Image
img = Image.open("rick-morty.png")

# If you want a greyscale image, simply convert it to the L (Luminance) mode:
new_img = img.convert('L')
new_img.show()

# Or save it to a file
# new_img.save('rick-morty-L.png')

Kết quả hơi khác so code thủ công ở trên một xíu, ví dụ cái màu áo của Morty ở trên là

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
8 nhưng ở dưới là
import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
9

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

2. Thay đổi độ tương phản (contrast)

Để thay đổi độ tương phản của pixel bằng

#pseudo code
if brightness > 0
    shadow = brightness
    highlight = 255
else:
    shadow = 0
    highlight = 255 + brightness
new_img = ((highlight - shadow)/255)*old_img + shadow
0 khá đơn giản

from PIL import Image, ImageEnhance
# PIL accesses images in Cartesian co-ordinates, so it is Image[columns, rows]
img = Image.open("rick-morty.png")

# Enhance constrast
enhancer = ImageEnhance.Contrast(img)
for i in range(1, 8):
    factor = i / 4.0
    new_img = enhancer.enhance(factor)
    new_img.show()
    # Or save it to file
    # new_img.save('rick-morty-%s.png' % i)

Trong đó thì factor là một giá trị để kiểm soát độ tương phản, 1.0 là tương đương hình gốc, còn thấp hơn 1.0 là giảm độ tương phản vân vân và mây mây.

factor – A floating point value controlling the enhancement. Factor 1.0 always returns a copy of the original image, lower factors mean less color (brightness, contrast, etc), and higher values more. There are no restrictions on this value.

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

Mình cũng không rõ Pillow thay đổi độ tương phản bằng cách nào, nhưng về lý thuyết chung thì làm tăng/giảm contrast là làm tối (darkening) nhưng pixel có giá trị dưới một mức nào đó, và làm sáng (lightening) những pixels có giá trị trên một mức nào đó. Độ chênh lệch này sẽ làm tăng hay giảm sự tương phản.

Các bạn có thể xem thêm công thức thay đổi độ tương phản của pixel ở đây, nhưng kết quả từ công thức này không ổn lắm nên mình không post kết quả ở đây.

3. Thay đổi độ sáng (brightness)

Để thay đổi độ sáng của ảnh bằng Pillow cũng rất đơn giản, ta làm như sau:

from PIL import Image, ImageEnhance
img = Image.open("rick-morty.png")
enhancer = ImageEnhance.Brightness(img)
# Lighter
new_img = enhancer.enhance(1.8)
# Darker
# new_img = enhancer.enhance(0.8)
new_img.show()

Để thay đổi độ sáng của pixels bằng cách thủ công cũng khá đơn giản, ta chỉ cần tăng hay giảm giá trị của từng pixel là được, chỉ cần lưu ý

#pseudo code
if brightness > 0
    shadow = brightness
    highlight = 255
else:
    shadow = 0
    highlight = 255 + brightness
new_img = ((highlight - shadow)/255)*old_img + shadow
1 giá trị đó sao cho nó nằm trong khoảng 0-255 là được.

from PIL import Image

def truncate(value):
    if (value < 0):
        return 0
    if (value > 255):
        return 255
    return value

if __name__ == "__main__":
    img = Image.open('rick-morty.png')
    pixels = img.load()

    img_new = Image.new(img.mode, img.size)
    pixels_new = img_new.load()
    brightness = 20
    for i in range(img_new.size[0]):
        for j in range(img_new.size[1]):
            r, b, g = pixels[i,j]
            _r = truncate(r + brightness)
            _b = truncate(b + brightness)
            _g = truncate(g + brightness)
            pixels_new[i,j] = (_r, _b, _g, 255)
    img_new.show()

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

4. Làm mờ (Gaussian blur)

Guassian blur Phương pháp làm mờ hình ảnh sử dụng Gussian function để giảm nhiễu và chi tiết trên bức ảnh.

Giải thích ngắn gọn thì cái ma trận 3x3 trong hình được gọi là

#pseudo code
if brightness > 0
    shadow = brightness
    highlight = 255
else:
    shadow = 0
    highlight = 255 + brightness
new_img = ((highlight - shadow)/255)*old_img + shadow
2. Chúng ta áp dụng cái filter như hình cho từng pixel thì cuối cùng chúng ta sẽ có một hình đã được làm mờ. Để sẽ giải thích chi tiết ở các bài sau.

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python
*Nguồn Digital Image processing

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
0

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

5. Làm tối 4 góc (vignette) sử dụng OpenCV và numpy

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
1

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

Cơm thêm

Phần này không liên quan tới xử lý hình ảnh ở trên

Tìm các cạnh bằng phương pháp Canny (Canny edge detection)

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
2

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

Vẽ countour của ảnh

Contour trong image proccesing là những đường nối những điểm liền nhau tạo thành hình dáng của vật trong ảnh (không phải contour trong trang điểm). Nó là một công cụ rất hữu ích trong nhận dạng và định danh các vật thể trong hình (object detection and recognition).

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
3

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

Nhận diện gương mặt bằng OpenCV

Sử dụng Haar Cascade classifier của OpenCV. Tải về file haarcascade_frontalface_default.xml ở đây

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted
4

Hướng dẫn change image contrast python - thay đổi độ tương phản hình ảnh python

Subscribe to Koodibar

Get the latest posts delivered right to your inbox