1

I would like to create following 2x2 image from numpy array using OpenCV.

2x2 image that consists of 1x1 tiles with colors blue, green, red and blue

I tried to create it with this code snippet.

import cv2
import numpy as np

blue = (255, 0, 0)
green = (0, 255, 0)
red = (0, 0, 255)

image = np.array([
    [blue, green],
    [red, blue]
])

cv2.imwrite('2x2.jpg', image)

I used BGR color format, yet when I view the output image, I see a colorless image.

colorless 2x2 image

What am I missing?

Environment

  • OpenCV 4.5.1.48
  • Python 3.9.1
  • Windows 10
7
  • 1
    With such a small image, it might be that the JPEG encoding is over compressing your original data. Try saving the file as a PNG instead, with cv2.imwrite('2x2.png', image). Commented Apr 28, 2021 at 22:46
  • 1
    Good point about jpg compression for images smaller than the jpg 8x8 block size. Commented Apr 28, 2021 at 23:10
  • 1
    @fmw42 It's not about the size, same happens if you tile this pattern. It's the effect of chroma subsampling used by JPEG. I think 4:2;0 variant (the most common), which would mean that colour is sampled at half the resolution (i.e. one sample for a 2x2 tile). Seems to fit, the result appears to only have varying luminance and same hue. Really shows why JPEG is bad choice for synthetic images like this. Commented Apr 29, 2021 at 9:29
  • 2
    OpenCV doesn't provide a way to directly control the subsampling method, however there is a side effect -- when you specify both IMWRITE_JPEG_LUMA_QUALITY and IMWRITE_JPEG_CHROMA_QUALITY and they are not equal, subsampling is turned off: github.com/opencv/opencv/blob/3.4/modules/imgcodecs/src/… | Unfortunately this needs JPEG_LIB_VERSION >= 70, and sadly the library shipped with OpenCV and used to build the standard releases (at least on Windows) is only version 62. Commented Apr 29, 2021 at 9:59
  • 1
    If JPEG format is required, Pillow allows direct control over subsampling: Image.fromarray(image[...,::-1]).save('2x2_PIL.jpg', quality=100, subsampling=0) Commented Apr 29, 2021 at 10:07

2 Answers 2

2

I think the jpg compressing method cause this issue on a few pixel shaped images

Instead of:

cv2.imwrite('2x2.jpg', image)

try to save it as png:

cv2.imwrite('2x2.png', image)

and always use uint8 on image array.

Sign up to request clarification or add additional context in comments.

Comments

2

I believe that your issue may be not specifying the dtype for your array. The following works fine for me in Python/OpenCV.

import cv2
import numpy as np

blue = (255, 0, 0)
green = (0, 255, 0)
red = (0, 0, 255)

image = np.array([
    [blue, green],
    [red, blue]
], dtype=np.uint8)

image = cv2.resize(image, (200,200), interpolation = cv2.INTER_AREA)

cv2.imwrite('2x2.jpg', image)

enter image description here

3 Comments

This doesn't solve it. When you change the size from (200, 200) to (2, 2) the output is the same colorless image. Specifying the dtype alone does nothing.
It works fine for me. If I remove the dtype, the resize crashes for me with an OpenCV error message. Sorry, if it does not work for you. I am using Python 3.7.5 and OpenCV 3.4.8
I use OpenCV 4.5.1.48 and if I remove the dtype it produces the same output. No crashes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.