OpenCV, editing an image list directly leads to inaccuracies
Question:
I was learning OpenCV with python, and tried to edit a section of pixels in an image.
import cv2
img1 = cv2.imread('Assets/chess.jpg', 1)
for row in range(20, 50):
for column in range(20, 50):
img1[row][column] = [255, 0, 0]
cv2.imwrite('Assets/new_chess.jpg', img1)
In the code I am setting all the pixels to [255, 0, 0] which should just be blue.
However, what I get is this:
I get a square that is blue but with a darker border
When I went back and printed the BGR value of a pixel on the corner of the square I got [155 12 15].
Printing a pixel in the middle gave me [255 0 7].
I don’t understand why the values aren’t [255, 0, 0] like I set them to be.
Answers:
You are saving the image as .jpg
format, which is a lossy compression algorithm.
In short, whenever a .jpg
image is saved, the algorithm transforms the image into a bunch of sine waves, and cut out several sine waves to reduce the file size (thus, a compression algorithm). That’s why the input file and the output file is not consistent.
Furthermore, you tend to notice significant changes on the edge of objects because sine waves describing edges are most likely to be eliminated due to the algorithm specification, while the constant part are less affected. You can see the value in the middle did not change too much, but pixels near the edge did.
As suggested by @stateMachine, you should save the image with a lossless compression algorithm, .png
for example, in order not to loose these details. (the size of output file will be larger, of course).
If you are curious, great explanation of JPEG (.jpg
) compression algorithm from Computerphile would help:
https://www.youtube.com/watch?v=n_uNPbdenRs
I was learning OpenCV with python, and tried to edit a section of pixels in an image.
import cv2
img1 = cv2.imread('Assets/chess.jpg', 1)
for row in range(20, 50):
for column in range(20, 50):
img1[row][column] = [255, 0, 0]
cv2.imwrite('Assets/new_chess.jpg', img1)
In the code I am setting all the pixels to [255, 0, 0] which should just be blue.
However, what I get is this:
I get a square that is blue but with a darker border
When I went back and printed the BGR value of a pixel on the corner of the square I got [155 12 15].
Printing a pixel in the middle gave me [255 0 7].
I don’t understand why the values aren’t [255, 0, 0] like I set them to be.
You are saving the image as .jpg
format, which is a lossy compression algorithm.
In short, whenever a .jpg
image is saved, the algorithm transforms the image into a bunch of sine waves, and cut out several sine waves to reduce the file size (thus, a compression algorithm). That’s why the input file and the output file is not consistent.
Furthermore, you tend to notice significant changes on the edge of objects because sine waves describing edges are most likely to be eliminated due to the algorithm specification, while the constant part are less affected. You can see the value in the middle did not change too much, but pixels near the edge did.
As suggested by @stateMachine, you should save the image with a lossless compression algorithm, .png
for example, in order not to loose these details. (the size of output file will be larger, of course).
If you are curious, great explanation of JPEG (.jpg
) compression algorithm from Computerphile would help:
https://www.youtube.com/watch?v=n_uNPbdenRs