OpenCV, editing an image list directly leads to inaccuracies


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.

Asked By: Artyom Yesayan



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:

Answered By: Khoa LT
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.