Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

imdecode returns None Python opencv2

Look at this code,

img = cv2.imread("image2.jpg",0)
img_str = cv2.imencode('.jpg', img)[1] #Encodes and stores in buffer
print(img_str)

#for i,item in enumerate(img_str):    }  THIS
 #   img_str[i] = 255-item            }  IS CONFUSING

nparr = np.frombuffer(img_str, np.uint8)
img2 = cv2.imdecode(nparr, cv2.IMREAD_COLOR)

My question is without this,

#for i,item in enumerate(img_str):    }  THIS
 #   img_str[i] = 255-item            }  IS CONFUSING

The code runs fine imdecode returns the same! But however when I uncomment it imdecode returns None

Opencv docs say

If the buffer is too short or contains invalid data, the empty matrix/image is returned.

What exactly is the invalid data that makes imdecode return none? Or any other mistake?

like image 876
void Avatar asked Feb 09 '18 06:02

void


People also ask

What does cv2 Imdecode return?

cv2. imdecode() function reads data from specified memory cache and converts (decodes) data into image format; it is mainly used to recover images from network transmission data. cv2.

What is imdecode?

imdecode() function is used to read image data from a memory cache and convert it into image format. This is generally used for loading the image efficiently from the internet. Syntax: cv2.imdecode(buf,flags)


1 Answers

I misunderstood your question before, but now your comments make it clearer.

When you encode an image in '.jpg' it is not a pixel array as before, but an array of bytes that represents a jpeg image. It will be the equivalent to read the bytes of the image directly with native functions.

If you transform each byte, it won't be able to decode it correctly, and your data will be invalid.

Let's examine the data a little bit more carefully:

First, we load the image and encode the data

# Exactly what you have to load and encode
import cv2
import numpy as np
img = cv2.imread("image2.jpg",0)
img_str = cv2.imencode('.jpg', img)[1]

Now, lets flatten the image array and see the first 10 pixels ( I use a random image I had in my drive):

img.flatten()[0:10]

This gives me:

[191, 191, 191, 191, 191, 191, 191, 191, 191, 191]

Now, lets show the first 10 bytes of the encoded one:

print(img_str.flatten()[0:10])

And I get:

[255 216 255 224   0  16  74  70  73  70]

As you can see, it is totally different numbers as before.... and not only that, At least the 2 first bytes gives information about the image as it is explain in the link I put a little before.

Start of image is the following code:

0xFF, 0xD8

That if you put it in decimal numbers it will give you:

255 216

Which is the first 2 bytes of the byte array... If you subtract 255-byte for all bytes, then the initial part will be 0 39 which will be an invalid syntax for the decoder to parse it.

In conclusion, do not change the image bytes after encoding it, change them before encoding it if needed, and try to also use OpenCV's function or from numpy to do it faster, the loop takes quite long in python. To invert the image and then encode it is the following code:

import cv2
import numpy as np

img = cv2.imread("image2.jpg",0)
invImg = cv2.bitwise_not(img) # equivalent to 255-img
img_str = cv2.imencode('.jpg', invImg )[1] 
img2 = cv2.imdecode(nparr, cv2.IMREAD_COLOR)

Another thing to consider, if you have an image and encode it and decode it in jpg, it WON'T BE THE SAME IMAGE, because jpg is a lossy compression, and it will have some small differences.

like image 192
api55 Avatar answered Oct 28 '22 10:10

api55