Mahi
Mahi

Reputation: 107

Reading an image to OpenCV (Numpy) by an input uint8 array

I am trying to develop an application which upload an image by using some Javascript codes. The Javascript code return me an array with the size equal to its size. so if I have a 4k size jpg image, it returns to me (approximate) 4,000 bytes of image data with the type of unit8. It is a python list like below.

[137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 50, 0, 0, 0, 50, 8, 6, 0, 0, 0, 30, 63, 136, 177, 0, 0, 0, 1, 115, 82, 71, 66, 1, 217, 201, 44, 127, 0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 11,
19, 0, 0, 11, 19, 1, 0, 154, 156, 24, 0, 0, 12, 76, 73, 68, 65, 84, 120, 156, 205, 90, 9, 116, 84, 85, 18, 125, 85, 191, 155, 69, 136, 6, 81, 143, 204, 184, 224, 130, 251, 58, 234, 168, 227, 56, 42, 46, 99, 0, 145
, 221, 153, 1, 68, 22, 9, 4, 18, 72, 128, 132, 64, 22, 146, 16, 18, 8, 4, 8, 73, 200, 0, 178, 4, 68, 86, 89, 195, 190, 139, 130, 65, 16, 5, 113, 1, 4, 21, 20, 16, 81, 32, 64, 72, 250, 85, 205, 253, 29, 228, 140, 1
03, 28, 108, 9, 33, 212, 57, 117, 222, 79, 247, 239, 247, 235, 190, 170, 186, 85, 245, 193, 152, 75, 64, 236, 60, 67, 190, 5, 166, 186, 46, 50, 84, 174, 141, 36, 147, 59, 74, 180, 39, 167, 180, 11, 229, 74, 123, 2
06, 181, 221, 157, 116, 219, 143, 250, 105, 154, 19, 103, 211, 169, 124, 155, 159, 235, 185, 83, 13, 233, 108, 122, 192, 206, 50, 233, 50, 139, 18, 101, 9, 215, 214, 105...]

Now I have above byte array, I would like to know how to read above array in OpenCV or by using Numpy?

I have written some codes by imdecode and imread but none of them work properly.

import cv2
img = cv2.imdecode(np.asarray(image_array), cv2.IMREAD_UNCHANGED)

The above codes always return me null images. Is this possible to read an image in OpenCV by using above array?

Upvotes: 0

Views: 4414

Answers (2)

Mark Setchell
Mark Setchell

Reputation: 207385

If you look at the first few elements of your list, you will see it is classic PNG file signature (magic number), or, in hex:

89 50 4e 47 0d 0a 1a 0a

where 50 is ASCII P, 4e is ASCII N and 47 is G - spelling PNG. That means your Javascript has sent you a PNG-encoded image.

So, you need the following:

import cv2
import numpy as np

L = [137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 64, 0, 0, 0, 64, 8, 2, 0, 0, 0, 37, 11, 230, 137, 0, 0, 0, 4, 103, 65, 77, 65, 0, 0, 177, 143, 11, 252, 97, 5, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0, 122, 38, 0, 0, 128, 132, 0, 0, 250, 0, 0, 0, 128, 232, 0, 0, 117, 48, 0, 0, 234, 96, 0, 0, 58, 152, 0, 0, 23, 112, 156, 186, 81, 60, 0, 0, 0, 6, 98, 75, 71, 68, 0, 255, 0, 255, 0, 255, 160, 189, 167, 147, 0, 0, 0, 7, 116, 73, 77, 69, 7, 228, 9, 3, 7, 16, 45, 84, 246, 102, 10, 0, 0, 0, 112, 73, 68, 65, 84, 104, 222, 237, 215, 177, 9, 192, 64, 12, 4, 65, 25, 222, 253, 151, 108, 23, 241, 193, 34, 152, 173, 224, 6, 69, 154, 89, 222, 115, 230, 212, 27, 174, 58, 0, 0, 0, 0, 0, 0, 155, 59, 239, 188, 245, 134, 59, 192, 250, 11, 0, 0, 0, 0, 0, 0, 108, 14, 160, 14, 160, 14, 160, 14, 160, 14, 160, 206, 83, 95, 7, 80, 7, 80, 7, 80, 7, 80, 7, 80, 7, 80, 7, 80, 7, 80, 7, 80, 183, 31, 224, 169, 7, 0, 0, 0, 0, 216, 220, 122, 192, 243, 205, 87, 111, 184, 234, 7, 229, 134, 4, 235, 125, 72, 121, 243, 0, 0, 0, 37, 116, 69, 88, 116, 100, 97, 116, 101, 58, 99, 114, 101, 97, 116, 101, 0, 50, 48, 50, 48, 45, 48, 57, 45, 48, 51, 84, 48, 55, 58, 49, 54, 58, 52, 53, 43, 48, 48, 58, 48, 48, 156, 134, 199, 95, 0, 0, 0, 37, 116, 69, 88, 116, 100, 97, 116, 101, 58, 109, 111, 100, 105, 102, 121, 0, 50, 48, 50, 48, 45, 48, 57, 45, 48, 51, 84, 48, 55, 58, 49, 54, 58, 52, 53, 43, 48, 48, 58, 48, 48, 237, 219, 127, 227, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130]

# Decode the PNG-encoded image
im = cv2.imdecode(np.array(L, dtype=np.uint8), cv2.IMREAD_UNCHANGED)

enter image description here


As you didn't provide your list, I did the following to replicate your starting position...

First, make a small PNG image with ImageMagick:

magick -size 64x64 gradient:black-magenta PNG24:a.png

Then, slurp all the bytes from the PNG-encoded file and make them into a list:

with open('a.png', 'rb') as image:
    data = image.read()
L = list(data)

Keywords: Python. image processing, OpenCV, decode, encoded, Javascript, image.

Upvotes: 1

LongToeBoy
LongToeBoy

Reputation: 195

most likely javascript will give you image in base64. so you just need to first decode and then make it file like object to open with opencv

import base64
import numpy as np
import cv2

with open("test.jpg", "rb") as f:
    im_b64 = base64.b64encode(f.read())

im_bytes = base64.b64decode(im_b64)
im_arr = np.frombuffer(im_bytes, dtype=np.uint8)  # im_arr is one-dim Numpy array
img = cv2.imdecode(im_arr, flags=cv2.IMREAD_COLOR)

[EDIT]

on the javascript side. its easier to use base64 images and this is the example how its being done

this is the html chunk how im uploading file. just a regular input type

<input type="file" class="custom-file-input" name="image" id="image" onchange=saveimgs(this)
                multiple />

this is actual javascript that is making file into base64 img

function saveimgs(a) {
    Array.prototype.forEach.call(a.files, (img) => {
        var reader = new FileReader();
        reader.onload = function(e) {
            var base64img = e.target.result;
            imgs.push(base64img); //push base64 representation of the image to imgs array                
        };
        reader.readAsDataURL(img);
    });
}

after that you can send this array containing base64 images to python with json

Upvotes: 0

Related Questions