Apply Function foreach Pixel in Numpy Array - python

I have a function like:
def calcChromaFromPixel(red, green, blue):
r = int(red)
g = int(green)
b = int(blue)
return math.sqrt(math.pow(r - g, 2) +
math.pow(r - b, 2) +
math.pow(g - b, 2))
and I have an RGB Image, which is already converted into an numpy array with a shape like [width, height, 3], where 3 are the color channels.
What I want to do is to apply the method to every pixel and build the mean from the result. I already have done the obvious thing and iterated over the array with two loops, but that seems to be a really slow thing to do... Is there a faster and prettier way to do that?!
Thanks :)

Code:
import math
import numpy as np
np.random.seed(1)
# FAKE-DATA
img = np.random.randint(0,255,size=(4,4,3))
print(img)
# LOOP APPROACH
def calcChromaFromPixel(red, green, blue):
r = int(red)
g = int(green)
b = int(blue)
return math.sqrt(math.pow(r - g, 2) +
math.pow(r - b, 2) +
math.pow(g - b, 2))
bla = np.zeros(img.shape[:2])
for a in range(img.shape[0]):
for b in range(img.shape[1]):
bla[a,b] = calcChromaFromPixel(*img[a,b])
print('loop')
print(bla)
# VECTORIZED APPROACH
print('vectorized')
res = np.linalg.norm(np.stack(
(img[:,:,0] - img[:,:,1],
img[:,:,0] - img[:,:,2],
img[:,:,1] - img[:,:,2])), axis=0)
print(res)
Out:
[[[ 37 235 140]
[ 72 137 203]
[133 79 192]
[144 129 204]]
[[ 71 237 252]
[134 25 178]
[ 20 254 101]
[146 212 139]]
[[252 234 156]
[157 142 50]
[ 68 215 215]
[233 241 247]]
[[222 96 86]
[141 233 137]
[ 7 63 61]
[ 22 57 1]]]
loop
[[ 242.56545508 160.44313634 138.44132331 97.21111048]
[ 246.05283985 192.94040531 291.07730932 98.66103588]
[ 124.99599994 141.90842117 207.88939367 17.20465053]
[ 185.66636744 133.02631319 77.82030583 69.29646456]]
vectorized
[[ 242.56545508 160.44313634 138.44132331 97.21111048]
[ 246.05283985 192.94040531 291.07730932 98.66103588]
[ 124.99599994 141.90842117 207.88939367 17.20465053]
[ 185.66636744 133.02631319 77.82030583 69.29646456]]

Related

Slicing based on boundingRect returns empty ndarray

I'm working on delaunay triangulation and trying to reach same results on two different webcam frames (two different USB cameras). Slicing returns empty ndarray on the other one.
Returns empty:
source_triangle = np.array([tr1_pt1, tr1_pt2, tr1_pt3], np.int32)
source_rectangle = cv2.boundingRect(source_triangle) #gives values like 819, 468, 43, 62
(xu, yu, wu, hu) = source_rectangle
cropped_source_rectangle = sourceframe[y: yu + hu, x: xu + wu] #returns []
Works like it should:
destination_triangle = np.array([tr2_pt1, tr2_pt2, tr2_pt3], np.int32)
destination_rectangle = cv2.boundingRect(destination_triangle) #gives values like 985, 441, 67, 43
(x, y, w, h) = destination_rectangle
cropped_destination_rectangle = destinationframe[y: y + h, x: x + w] #gives values like
[[[34 35 39]
[34 35 39]
[34 35 39]
...
...
[35 35 42]
[35 34 44]
[35 34 44]]]
If I print values from destinationframe and sourceframe, both have a format similar to this: [[[254 253 255] [254 253 255] [254 253 255] ... [ 89 88 90] [ 89 88 90] [ 89 88 90]]]
EDIT: Just adding that the frame dimensions are not identical: sourceframe starts with [224 223 225] for example.
I have been stuck on this for a while, any help is appreciated!

What should I do after converting image to numpy array?

I am doing a project in which I have image of electricity meter reading. I need to extract the digits in the image.
I converted the image to a numpy array using the PIL Image function.
This is the code I typed
import numpy as np
from PIL import Image
img_data = Image.open('meter1.jpg' )
img_arr = np.array(img_data)
print(img_arr)
I got this numpy array as the output
[[[ 2 96 10]
[ 2 96 10]
[ 2 96 10]
...
[ 18 144 47]
[ 13 141 48]
[ 10 139 46]]
[[ 11 105 19]
[ 10 106 19]
[ 10 104 18]
...
[ 28 156 59]
[ 26 156 60]
[ 24 155 59]]
[[ 19 115 26]
[ 16 115 25]
[ 17 113 24]
...
[ 30 162 60]
[ 28 164 62]
[ 26 165 64]]
...
[[ 0 126 18]
[ 0 126 18]
[ 0 126 18]
...
[ 4 211 77]
[ 4 211 79]
[ 6 213 83]]
[[ 0 126 18]
[ 0 126 18]
...
[ 4 212 76]
[ 4 211 79]
[ 6 213 83]]
[[ 1 124 17]
[ 1 124 17]
[ 1 124 17]
...
[ 5 211 76]
[ 5 210 79]
[ 7 212 81]]]
How do I use this numpy array to extract the numerical values or the digits or the numbers from this image?
It is a seven segment display. Was is useful to convert the image to numpy array? Is there any other approach to do this. I have not done much of hand-on python so please help
it's better first to try doing some coding, because this way your coding skills improve. by the way, I wrote a script that save your digits into separate image files. hope it helps you in your project and improving your skills.
import numpy as np
from PIL import Image
import os
directory,filename = os.path.split(__file__)
#x = np.array([ [ [255,0,0], [0,255,0], [0,0,255] ],[ [0,0,0],[128,128,128],[2,5,200] ] ],dtype=np.uint8)
main_img = Image.open('img.jpg')
x = np.array(main_img)
print(x)
#print(x[1][1] )# x[row number][column number]
#print(x.shape[1] )# x.shape = # of rows,# of cols
data_cols = []
bg_color = x[0][0]
start = False
start_id = -1
for j in range(0,x.shape[1]):
for i in range(0,x.shape[0]):
if (x[i][j][0] < 5) and (x[i][j][2] < 10):
if not start:
start_id = j
start = True
break
if i == x.shape[0]-1:
start = False
end_id = j
if start_id>=0:
data_cols.append([start_id,end_id])
start_id=-1
print("Number of digits>",len(data_cols))
images = []
for i in range(0,len(data_cols)):
images.append(x[:,data_cols[i][0]:data_cols[i][1]])
i = 0
for im_array in images:
im = Image.fromarray(im_array,'RGB')
im.save(directory + "\\" + str(i) + ".png")
i += 1

Fancy indexing to replace the values of an N dimensional array?

I am currently working with a numpy array containing pixel color information of shape (width, height, 3).
I would like to be able to replace colors in the original array, with colors described in a new array and to do this WITHOUT loops if possible.
I have tried indexing it with fancy index's but was not quite sure how to index properly.
Optimally the function would like something like this:
>>>import numpy as np
>>>imgdat = np.random.randint(0, 255, size=(2, 2, 3))
>>>imgdat
[[[138 149 41]
[100 186 136]]
[[181 202 169]
[205 247 195]]]
>>>pixels = np.random.randint(0, imgdat.shape[0], size=(2, 2))
>>>pixels
[[1,0]
[0,1]]
>>>colors = np.random.randint(0, 255, size=(2, 3))
>>>colors
[[ 16 229 138]
[ 86 76 209]]
######apply the function#######
>>>filledimgdat = fillPixels(imgdat, pixels, colors)
>>>filledimgdat
[[[ 138 149 41]
[ 86 76 209]]
[[ 16 229 138]
[205 247 195]]]
EDIT:
Because my originally description was a little unclear, what I am trying to do is replace specific colors in imgdat at specific index's. If anybody can think of a better way to format the datatypes or handle the info to simplify an operation like this, that would also be welcome.

subtracting RGB values from an Image in Python

I'm working in a project where I need to subtract the RGB values from an Image. In example I want to subtract the BLUE channel from RED, so RED gets the difference value of the subtraction.
I have the next properties of the image:
Dimension:1456x2592,
bpp:3
The image I'm using gives me the following arrays:
[[[ 63 58 60]
[ 63 58 60]
[ 64 59 61]
...,
[155 155 161]
[155 155 161]
[155 155 161]]
[[ 58 53 55]
[ 60 55 57]
[ 62 57 59]
...,
[157 157 163]
[157 157 163]
[158 158 164]]
I know those are the values(RGB) from the image, so now I move on to do the code (I based on this code)
import cv2
import numpy as np
from PIL import Image
# read image into matrix.
m = cv2.imread("ITESO.jpeg")
# get image properties.
h,w,bpp = np.shape(m)
# iterate over the entire image.
# BLUE = 0, GREEN = 1, RED = 2.
for py in range(0,h):
for px in range(0,w):
#m[py][px][2] = 2
n = m[py][px][2] //n takes the value of RED
Y = [n, 0, 0] //I create an array with [RED, 0, 0]
m, Y = np.array(m), np.array(Y)
m = np.absolute(m - Y) //Get the matriz with the substraction
y = 1
x = 1
print (m)
print (m[x][y])
#display image
#cv2.imshow('matrix', m)
#cv2.waitKey(0)
cv2.imwrite('new.jpeg',m)
img = Image.open('new.jpeg')
img.show()
img = Image.open('new.jpeg').convert('L')
img.save('new_gray_scale.jpg')
img.show()
When I print the J matrix it gives the following arrays:
B,G,R
Blue = BLUE - RED
[[[ 3 58 60]
[ 3 58 60]
[ 4 59 61]
...,
[ 95 155 161]
[ 95 155 161]
[ 95 155 161]]
[[ 2 53 55]
[ 0 55 57]
[ 2 57 59]
...,
[ 97 157 163]
[ 97 157 163]
[ 98 158 164]]
But I'm not able to open the new image and if I set one RGB channel to one value it shows me the image. I use the next lines for that:
import cv2
import numpy as np
# read image into matrix.
m = cv2.imread("python.png")
# get image properties.
h,w,bpp = np.shape(m)
# iterate over the entire image.
for py in range(0,h):
for px in range(0,w):
m[py][px][0] = 0 //setting channel Blue to values of 0
# display image
cv2.imshow('matrix', m)
cv2.waitKey(0)
How can I subtract the RGB channels from each other?
PS: In MatLab it works like a charm, but I'm not able to do it in python.
Pay attention that this operation is changing the dtype of the matrix (image) from uint8 to int32, and this can cause other problems. A better way (and more efficient) to do this, IMO, is this:
import cv2
import numpy as np
img = cv2.imread('image.png').astype(np.float) # BGR, float
img[:, :, 2] = np.absolute(img[:, :, 2] - img[:, :, 0]) # R = |R - B|
img = img.astype(np.uint8) # convert back to uint8
cv2.imwrite('new-image.png', img) # save the image
cv2.imshow('img', img)
cv2.waitKey()
Code manipulating RGB negative values to zero...
m = cv2.imread("img.jpg")
# get image properties.
h,w,bpp = np.shape(m)
# iterate over the entire image.
# BLUE = 0, GREEN = 1, RED = 2.
for py in range(0,h):
for px in range(0,w):
n = m[py][px][1]
Y = [0, 0, n]
m, Y = np.array(m), np.array(Y)
a = (m - Y)
if (a[py][px][0] <=0): #if Blue is negative or equal 0
a[py][px][0] = 0 #Blue set to 0
cv2.imwrite('img_R-G.jpg',a)
img = Image.open('img_R-G.jpg').convert('L')
img.save('img_R-G_GS.jpg')

Inverting numpy array image which might be uint8, uint16,

Is there a prettier way to do this? Specifically, are these max values available through the numpy API? I haven't been able to find them in the API, although they are easily found here in the docs.
MAX_VALUES = {np.uint8: 255, np.uint16: 65535, np.uint32: 4294967295, \
np.uint64: 18446744073709551615}
try:
image = MAX_VALUES[image.dtype] - image
except KeyError:
raise ValueError, "Image must be array of unsigned integers."
Packages like PIL and cv2 provide convenient tools for inverting an image, but at this point in the code I have a numpy array -- more sophisticated analysis follows -- and I'd like to stick with numpy.
Try doing
image ^= MAX_VALUES[image.dtype]
By the way, you do not need to define MAX_VALUES yourself. NumPy has them built-in:
import numpy as np
h, w = 100, 100
image = np.arange(h*w).reshape((h,w)).astype(np.uint8)
max_val = np.iinfo(image.dtype).max
print(max_val)
# 255
image ^= max_val
print(image)
# [[255 254 253 ..., 158 157 156]
# [155 154 153 ..., 58 57 56]
# [ 55 54 53 ..., 214 213 212]
# ...,
# [ 27 26 25 ..., 186 185 184]
# [183 182 181 ..., 86 85 84]
# [ 83 82 81 ..., 242 241 240]]

Categories