python function to change RGB values of an image - python

I have this function that solely displays the red RGB values of an image. However, I am confused about how the function works. Specifically, why is there a 0 in brackets in this line:
newimage[i][j] = [image[i][j][0], 0, 0]
How can I alter this function to swap the green and blue RGB values while keeping the red value the same?
from matplotlib.pyplot import imshow #command to display a 2D array as an image
from imageio import imread #command to read images from a file or url
coffee = imread('imageio:coffee.png') #Image
def RedImage(image):
newimage = ArrayOfZeros(400, 600)
for i in range(400):
for j in range(600):
newimage[i][j] = [image[i][j][0], 0, 0]
return newimage
imshow(RedImage(coffee))

In
newimage[i][j] = [image[i][j][0], 0, 0]
image[i][j] and newimage[i][j] presumably are arrays consisting of three values for red, green, and blue at a particular pixel location (i, j) in the image.
So image[i][j][0] is the red value of the original image which will also be used as the red value for the new image. The blue and green values of the new image will be 0.
The green value of the original image is image[i][j][1] and the blue value is image[i][j][2]. So in order to swap them in the new image, use the green value of the old image in the position of the blue value for the new image, and the blue value of the old image in the position of the green value for the new image.
newimage[i][j] = [image[i][j][0], image[i][j][2], image[i][j][1]]

Related

Image processing: counting individual number pixel in an mask image using Pillow and 3D Numpy

Please help me. I need some opinion on this problem.
I am trying to count individual number of R,G,B value of an mask image.
I have an image which is masked filled background with green and it mask a human with red and an object with blue.
The image size and data type are
(1536, 2048, 3)
uint8
I have tried to access the numpy array of pixels
img_path = "sample.png"
i = Image.open(img_path, 'r')
data = asarray(i)
array = np.array(i)
But the array only show the background green. Something like below.
[[[ 0, 255, 0
0, 255,0]]]
It does not show red and blue color of an image
I have tried getpixel()
i = Image.open(img_path, 'r')
r, g, b = i.getpixel((0, 0))
print("Red: {}, Green: {}, Blue: {}".format(r, g, b))
It does not count the red and and blue color of mask image.
How to count the number of R,G,B pixel in mask image?
Where can I find read more about accessing and counting total number of pixels with numpy and pillow?
Please tell me anything related to this.
from PIL import Image
with Image.open('hopper.jpg') as im:
px = im.load()
r, g, b = px[x, y]
print(r, g, b)
This code worked for me. x and y pixel cordinates.
You can get full info from this

How to replace all pixels of a certain RGB value with another RGB value in OpenCV

I need to be able to replace all pixels that have a certain RGB value with another color in OpenCV.
I’ve tried some of the solutions but none of them worked for me.
What is the best way to achieve this?
TLDR; Make all green pixels white with Numpy:
import numpy as np
pixels[np.all(pixels == (0, 255, 0), axis=-1)] = (255,255,255)
I have made some examples of other ways of changing colours here. First I'll cover exact, specific RGB values like you asked in your question, using this image. It has three big blocks of exactly red, exactly green and exactly blue on the left and three gradual transitions between those colours on the right:
Here's the initial answer as above again:
#!/usr/bin/env python3
import cv2
import numpy as np
# Load image
im = cv2.imread('image.png')
# Make all perfectly green pixels white
im[np.all(im == (0, 255, 0), axis=-1)] = (255,255,255)
# Save result
cv2.imwrite('result1.png',im)
This time I define the colour names for extra readability and maintainability. The final line is the important point:
# Define some colours for readability - these are in OpenCV **BGR** order - reverse them for PIL
red = [0,0,255]
green = [0,255,0]
blue = [255,0,0]
white = [255,255,255]
black = [0,0,0]
# Make all perfectly green pixels white
im[np.all(im == green, axis=-1)] = white
Same result.
This time I make a re-usable mask of red pixels which I can use in subsequent operations. The final line with the assignment im[Rmask] = black is now particularly easy to read :
# Define some colours for readability - these are in OpenCV **BGR** order - reverse them for PIL
red = [0,0,255]
green = [0,255,0]
blue = [255,0,0]
white = [255,255,255]
black = [0,0,0]
# Make mask of all perfectly red pixels
Rmask = np.all(im == red, axis=-1)
# Make all red pixels black
im[Rmask] = black
This time I combine a mask of red and blue pixels so you can see the power of masks. The final line is the important point:
# Define some colours for readability - these are in OpenCV **BGR** order - reverse them for PIL
red = [0,0,255]
green = [0,255,0]
blue = [255,0,0]
white = [255,255,255]
black = [0,0,0]
# Make mask of all perfectly red pixels and all perfectly blue pixels
Rmask = np.all(im == red, axis=-1)
Bmask = np.all(im == blue, axis=-1)
# Make all red or blue pixels black
im[Rmask | Bmask] = black
And this time I make all non-red pixels into black - hopefully you are appreciating the power of masks now. The final line is the important point:
# Define some colours for readability - these are in OpenCV **BGR** order - reverse them for PIL
red = [0,0,255]
green = [0,255,0]
blue = [255,0,0]
white = [255,255,255]
black = [0,0,0]
# Make mask of all perfectly red pixels
Rmask = np.all(im == red, axis=-1)
# Make all non-red pixels black
im[~Rmask] = black
Up till now, we have only made some selection of pixels into a single new colour. What if we want to make some pixels one colour and all other pixels a different colour in a single pass? The final line is the important point:
# Define some colours for readability - these are in OpenCV **BGR** order - reverse them for PIL
red = [0,0,255]
green = [0,255,0]
blue = [255,0,0]
white = [255,255,255]
black = [0,0,0]
# Make mask of all perfectly red pixels
Rmask = np.all(im == red, axis=-1)
# Make all red pixels white AND at same time everything else black
im = np.where(np.all(im == red, axis=-1, keepdims=True), white, black)
If you want to affect a whole range of colours, rather than a specific RGB value, have a look here and here.
Keywords: Image processing, Python, prime, change colour, change color, prime.
Lets assume the 'certain' pixels which you need to change have the following RGB values:
[r,g,b] i.e. the pixels have R=r, G=g and B=b as color values.
Firstly you need to create a 2D mask of the same size as your image. Let the size be (X,Y). The mask should:
Have value 1 or True at index (x1,y1) if the corresponding pixels in image has RGB channels==[r,g,b]
Have value 0 or False at index (x2,y2) if the corresponding pixels in image has RGB channels!=[r,g,b]
To create this mask:
old_color = [r,g,b]
new_color = [r2,g2,b2]
height, width, channels = numpy.shape(image)
mask = numpy.zeros((height,width))
# iterate over all pixels in the image and assign 0 to the mask(x,y) if image(x,y) has channels==old_color
mask= [[1 if np.all(channels==[old_color]) else 0 for channels in row ] for row in image ]
Then find the coordinates of all the 1s in the mask, these are the coordinate where you need to assign the new color in the image. Simply use np.where() to find the coordinates.
mask = numpy.array(mask) # make sure that mask is a numpy array not a list of lists
# numpy.where would not work otherwise
coords_x, coord_y = np.where(mask>0)
Finally change the RGB values on these coordinates in the image with the new RGB value:
img_cp = image.copy()
img_cp[coords_x,coord_y,:]=new_color
Your selected pixels in the image have new colors now. You can check with matplotlib.pyplot.imshow(img_cp)

NumPy: Understanding values in colour matrix

I have an image which I have read and converted into a numpy array. I have then extracted each colour channel (R,G,B) of the image into three separate arrays:
import cv2
import numpy as np
from sklearn.cluster import MeanShift, estimate_bandwidth
from sklearn.datasets.samples_generator import make_blobs
import matplotlib.pyplot as plt
from itertools import cycle
from PIL import Image
image = Image.open('sample_images/fruit_half.png').convert('RGB')
image = np.array(image)
red = image[:,:,2]
green = image[:,:,1]
blue = image[:,:,0]
When I print the value of the "red" array, I get the following output:
print(red)
[[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
...
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]]
I would like to know what do the numbers in the red, green and blue arrays represent. Do they represent the intensity of red/green/blue for a specific pixel? Any insights are appreciated.
They stand for the pixel intensity of each color channel in the image. If you print out image.shape you will be able to access its properties
print(image.shape)
You will get something like this
(93, 296, 3)
This tells us the (rows, columns, channels) in the image. In this case, the image has three channels. If you print out each individual channel, they represent pixel intensity ranging from 0-255. Every pixel is made up of the combination of these three channels. If instead you printed out the shape of the image and you got this
(93, 296, 1)
it means that the image only has one channel (a grayscale image).
One thing to note is that OpenCV follows BGR convention while PIL follows RGB. Currently, you are splitting backwards. To split channels using PIL you can do this
image = Image.open('1.jpg').convert('RGB')
image = np.array(image)
red = image[:,:,0]
green = image[:,:,1]
blue = image[:,:,2]
Remember PIL uses RGB format where red is in channel 0, green in channel 1, and blue in channel 2.
To split channels using OpenCV you can do this
image = cv2.imread('1.jpg')
b,g,r = cv2.split(image)
or
b = image[:,:,0]
g = image[:,:,1]
r = image[:,:,2]
Taking this image as an example, you can use a histogram to visualize the channels.
import cv2
from matplotlib import pyplot as plt
image = cv2.imread('1.jpg')
b,g,r = cv2.split(image)
blue = cv2.calcHist([b], [0], None, [256], [0,256])
green = cv2.calcHist([g], [0], None, [256], [0,256])
red = cv2.calcHist([r], [0], None, [256], [0,256])
plt.plot(blue, color='b')
plt.plot(green, color ='g')
plt.plot(red, color ='r')
plt.show()
Yes they represent intensity, each value is an a 8-bit value from 0 to 255. If a value is 0 the red pixel is completely off and 255 is completely on. Usually people just use the image an array (well, opencv list them in the order blue green red). The image array holds a rgb value at every pixel (try printing image). This a standard for images and can be explained here.
RGB picture is a digital matrix with 3 channel, each channel contain a value from 0 to 255 (if your dtype = uint8) to present the percentage of that color in that pixel. Look at the picture:
You can see that if we combine red and Green at 100% (mean 255), we have yellow, if we combine them in 100% together, we have white, etc. By this formula, each pixel will have x of Red and y of Green and z of Blue.
Example:
Therefore, the value you see in red channel is the percent of red color in your picture.
Hope this useful!

Changing pixel color using PIL on Python

I'm very new to programming, and I am learning more about image processing using PIL.
I have a certain task that requires me to change every specific pixel's color with another color. Since there are more than few pixels I'm required to change, I've created a for loop to access to every pixel. The script "works" at least, however the result is just a black screen with (0, 0, 0) color in each pixel.
from PIL import Image
img = Image.open('/home/usr/convertimage.png')
pixels = img.load()
for i in range(img.size[0]):
for j in range(img.size[1]):
if pixels[i,j] == (225, 225, 225):
pixels[i,j] = (1)
elif pixels[i,j] == (76, 76, 76):
pixels [i,j] = (2)
else: pixels[i,j] = (0)
img.save('example.png')
The image I have is a grayscale image. There are specific colors, and there are gradient colors near the borders. I'm trying to replace each specific color with another color, and then replace the gradient colors with another color.
However for the life of me, I don't understand why my output comes out with a single (0, 0, 0) color at all.
I tried to look for an answer online and friends, but couldn't come up with a solution.
If anyone out there knows what I'm doing wrong, any feedback is highly appreciated. Thanks in advance.
The issue is that your image is, as you said, greyscale, so on this line:
if pixels[i,j] == (225, 225, 225):
no pixel will ever equal the RGB triplet (255,255,255) because the white pixels will be simply the greyscale vale 255 not an RGB triplet.
It works fine if you change your loop to:
if pixels[i,j] == 29:
pixels[i,j] = 1
elif pixels[i,j] == 179:
pixels [i,j] = 2
else:
pixels[i,j] = 0
Here is the contrast-stretched result:
You may like to consider doing the conversion using a "Look Up Table", or LUT, as large numbers of if statements can get unwieldy. Basically, each pixel in the image is replaced with a new one found by looking up its current index in the table. I am doing it with numpy for fun too:
#!/usr/local/bin/python3
import numpy as np
from PIL import Image
# Open the input image
PILimage=Image.open("classified.png")
# Use numpy to convert the PIL image into a numpy array
npImage=np.array(PILimage)
# Make a LUT (Look-Up Table) to translate image values. Default output value is zero.
LUT=np.zeros(256,dtype=np.uint8)
LUT[29]=1 # all pixels with value 29, will become 1
LUT[179]=2 # all pixels with value 179, will become 2
# Transform pixels according to LUT - this line does all the work
pixels=LUT[npImage];
# Save resulting image
result=Image.fromarray(pixels)
result.save('result.png')
Result - after stretching contrast:
I am maybe being a bit verbose above, so if you like more terse code:
import numpy as np
from PIL import Image
# Open the input image as numpy array
npImage=np.array(Image.open("classified.png"))
# Make a LUT (Look-Up Table) to translate image values
LUT=np.zeros(256,dtype=np.uint8)
LUT[29]=1 # all pixels with value 29, will become 1
LUT[179]=2 # all pixels with value 179, will become 2
# Apply LUT and save resulting image
Image.fromarray(LUT[npImage]).save('result.png')

How do i fill color in each rectangle block using openCV and Python?

I want to fill color in each cell of following image.i have used for loops to fill these boxes with pixel by pixel.when use filling borders also get colored that is main problem here.
These are dimensions of cell.
Width: 20px;
Height: 20px;
Border Width: 20px;
when neighbor cells are connected their border width will be 4 px.
Original
Colored
So i don't want to color borders only region of cell(white part) shold be colored.
An image have three channels (R, G, B).
All the white blocks in image are white because they have 255 in pixels of all three channels.
To convert white blocks into red, first we read image matrix by using cv2 and then all the pixels having value 255 in channel-1 ("G") and channel-2 ("B") will be changed to 0. So, now we have pixel value 255 in channel-0 ("R") only. This way all white blocks of image gets changed to red colour block.
Two files are attached: 1. old_square.jpg 2. new_square.jpg
old_square.jpg have white colour square which are coloured into red colour, shown in new_square.jpg.
Check following script:
# libraries
import cv2
import numpy as np
import Image
# name of jpg image file
jpg_image_name = "old_square.jpg"
# reading jpg image and getting its matrix
jpg_image = cv2.imread(jpg_image_name)
jpg_image_mat = np.array(jpg_image)
# getting image features
pixel_value_to_replace = 255
rows, cols, channels = jpg_image_mat.shape
"""##########################################
An image have three channels (R, G, B). So,
putting 0 in other two channels to make image
red at white squares.
##########################################"""
# changing 255 to 0 in first channel
for i in range(rows):
for j in range(cols):
if(jpg_image_mat[i, j, 1] == pixel_value_to_replace):
jpg_image_mat[i, j, 1] = 0
# changing 255 to 0 in second channel
for i in range(rows):
for j in range(cols):
if(jpg_image_mat[i, j, 2] == pixel_value_to_replace):
jpg_image_mat[i, j, 2] = 0
# saving new modified matrix in image format
new_image = Image.fromarray(jpg_image_mat)
new_image.save("new_square.jpg")
old_square.jpg
new_square.jpg

Categories

Resources