How to use agglomerative clustering to quantize colors in an Image. For this I extract RGB vector for single pixel and this process require for all positions. So again how to extract all position rgb vectors.
im=Image.open('d:\eye.jpg')
r,g,b = im.convert('RGB')
r,g,b = rgb1.getpixel((1,1))
print r,g,b
this code only extract rgb vector value for only one pixel at a time. How to extract all the values simultaneously.
You can use numpy.array and convert the whole Image into a numpy.ndarray object:
import numpy as np
a = np.array(Image.open('d:\eye.jpg')).swapaxes(0,1)
Where a[i,j] is a position in this array that will give you the same result as rgb1.getpixel((i,j)) (with the difference that the latter returns a tuple).
Related
I get an image stored as an object from a camera that look like this (here reduced to make it understandable):
image = np.array([['#49312E', '#4A3327', '#493228', '#472F2A'],
['#452C29', '#49312E', '#4B3427', '#49312A'],
['#473026', '#472F2C', '#48302B', '#4C342B']])
is it possible to 'import' it as an 'image' in opencv?
I tried to look at the documentation of cv2.imdecode but could get it to work.
I could preprocess this array to get it to another format but I am not sure what could 'fit' to opencv.
Thank you for your help
This is a very succinct and pythonic (using NumPy) way to implement a conversion from your hexadecimal values matrix to an RGB matrix that could be read by OpenCV.
image = np.array([['#49312E', '#4A3327', '#493228', '#472F2A'],
['#452C29', '#49312E', '#4B3427', '#49312A'],
['#473026', '#472F2C', '#48302B', '#4C342B']])
def to_rgb(v):
return np.array([np.int(v[1:3],16), np.int(v[3:5],16) , np.int(v[5:7],16)])
image_cv = np.array([to_rgb(h) for h in image.flatten()]).reshape(3, 4, 3)
cv2.imwrite('result.png', image_cv)
OpenCV requires either a RGB or a BGR input, which is to say you need to give the values of Red Green Blue or Blue Green Red on a scale from 0-255 (8 bit). I have shared with you the code to convert your array to an image.
Initially, I count the number of rows to find the height in terms of pixels. Then I count the number of items in a row to find the width.
Then I create an empty array of the given dimensions using np.zeros.
I then go to each cell and convert the hex code to its RGB equivalent, using the following formula #RRGGBB, R = int(RR,16), G = int(GG, 16), B = int(BB, 16). This converts the hexadecimal string to int.
#!/usr/bin/env python3
import numpy as np
import re
import cv2
# Your image
image = np.array([['#49312E', '#4A3327', '#493228', '#472F2A'],
['#452C29', '#49312E', '#4B3427', '#49312A'],
['#473026', '#472F2C', '#48302B', '#4C342B']])
# Enter the image height and width
height = int(len(image[0]))
width = int(len(image[0][0]))
# Create numpy array of BGR triplets
im = np.zeros((height,width,3), dtype=np.uint8)
for row in range (height):
for col in range(width):
hex = image[row, col][1:]
R = int(hex[0:2],16)
G = int(hex[2:4],16)
B = int(hex[4:6],16)
im[row,col] = (B,G,R)
# Save to disk
cv2.imwrite('result.png', im)
I'm currently working on image superpixel SLIC segmentation with the package skimage.segmentation.
My original image is 3042*4032 (12Mpx). In skimage, the array's shape is (3042,4023,3). After the segmentation, I have around 3000 superpixels represented in a 3042*4032 array.
My goal is to find for each superpixel, the proportion of pixel which have their maximum value on the Red channel, the Blue channel and the Green channel.
I already have a function which give me the index of the maximum in the entire image :
def proportion_majoritaire_rgb_image(img):
""" In a pixel, which channel [R,G,B] has the maximum value ?
:param img: image (N,m) skimage rgb
:return: (N,m) array with indexes [0,1,2]
"""
return np.argmax(img, axis=2)
And by filtering the image on a single label, i can get the proportion of max RGB in a single label :
def proportion_majoritaire_rgb_label(img, matrice_label):
"""
:param img: image (N,m) skimage rgb
:param matrice_label: ndarray (N,m) labels SLIC
:return: (K, 3) array of K labels and 3 proportions
"""
indice_max_rgb = proportion_majoritaire_rgb_image(img)
n_pixel_max_rgb = []
for k in np.unique(image_grains_ble_slic).flat:
label_data = indice_max_rgb[matrice_label == k]
n_pixel_max_rgb.append(np.unique(label_data, return_counts=True)[1] / np.shape(label_data)[0])
return n_pixel_max_rgb
The issue is how to get this information for all my 3000 labels without this for loop ? It takes too much time to compute, is there any other way ?
The final output should be a ndarray (K,3) with K labels and for each channel RGB the proportion of pixels which have the maximum value.
Thanks in advance !
EDIT : Using np.unique(image_grains_ble_slic).flat as an iterator for the loop seems to be faster, but my goal of avoiding the for loop still stands
It's a little hacky because of a long-standing feature request for skimage.measure.regionprops to allow measuring multichannel images. But, we can hack it together with some repeated calls to regionprops_table, which gives us vectorised output:
from skimage import measure
index_max_rgb = np.argmax(image, axis=2)
max_index_images = [
(index_max_rgb == i).astype(float) for i in range(3)
]
proportions_per_channel = [
measure.regionprops_table(
image_grains_ble_slic,
intensity_image=intensity,
properties=('mean_intensity',),
)['mean_intensity']
for intensity in max_index_images
]
proportions = np.stack(proportions, axis=1)
By the way, be sure that you use start_label=1 with SLIC because regionprops ignores the 0 label as belonging to the background.
I have made myself a numpy array from a picture using
from PIL import Image
import numpy as np
image = Image.open(file)
np.array(image)
its shape is (6000, 6000, 4) and in that array I would like to replace pixel values by one number lets say this green pixel [99,214,104,255] will be 1.
I have only 4 such pixels I want to replace with a number and all other pixels will be 0. Is there a fast and efficient way to do so and what is the best way to minimize the size of the data. Is it better to save it as dict(), where keys will be x,y and values, will be integers? Or is it better to save the whole array as it is with the shape it has? I only need the color values the rest is not important for me.
I need to process such a picture as fast as possible because there is one picture every 5 minutes and lets say i would like to store 1 year of data. That is why I'd like to make it as efficient as possible time and space-wise.
If I understand the question correctly, you can use np.where for this:
>>> arr = np.array(image)
>>> COLOR = [99,214,104,255]
>>> np.where(np.all(arr == COLOR, axis=-1), 1, 0)
This will produce a 6000*6000 array with 1 if the pixel is the selected colour, or 0 if not.
How about just storing in a database: the position and value of the pixels you want to modify, the shape of the image, the dtype of the array and the extension (jpg, etc...). You can use that information to build a new image from an array filled with 0.
I tried using the PIL library to get a matrix consisting of arrays of pixels and RGB, however, I only get a one-dimensional array and I don’t understand how to form a matrix of them
img = Image.open("E:\\1f9114.png").convert('RGB')
obj = img.load()
width, height = img.size
for j in range(height):
for i in range(width):
matrix1=[i,j,obj[i,j]]
print(matrix1)
print()
I know that the matrix can turn out huge, and the usual sheet does not cope .I hope somebody will help, as it is important for me.
There are several issues with this code snippet:
matrix1 is always overridden. If you want to add pixels to an existing list, use list.append().
im.getdata() should be used to obtain a one-dimensional raw pixel list from the image.
Here is an example (adapted from here) to load pixels into a two-dimensional array that contains (r,g,b) tuples built using list comprehensions and slices.
pixels = list(img.getdata())
matrix1 = [pixels[i*width:(i+1)*width] for i in range(height)]
When I load an image with PIL and convert it into a NumPy array:
image = Image.open("myimage.png")
pixels = np.asarray(image)
The data is stored as [x][y][channel]. I.e., the value of pixels[3, 5, 0] will be the the (3, 5) pixel, and the red component of that pixel.
However, I am using a library which requires the image to be in the format [channel][x][y]. Therefore, I am wondering how I can do this conversion?
I know that NumPy has a reshape function, but this doesn't actually allow you to "swap" over the dimensions as I want.
Any help? Thanks!
In order to get the dimensions in the order that you want, you could use the transpose method as follows:
image = Image.open("myimage.png")
pixels = np.asarray(image).transpose(2,0,1)