Changing pixel color Python
I assume you're trying to use the Image
module. Here's an example:
from PIL import Image
picture = Image.open("/path/to/my/picture.jpg")
r,g,b = picture.getpixel( (0,0) )
print("Red: {0}, Green: {1}, Blue: {2}".format(r,g,b))
Running this on this image I get the output:
>>> from PIL import Image
>>> picture = Image.open("/home/gizmo/Downloads/image_launch_a5.jpg")
>>> r,g,b = picture.getpixel( (0,0) )
>>> print("Red: {0}, Green: {1}, Blue: {2}".format(r,g,b))
Red: 138, Green: 161, Blue: 175
EDIT:
To do what you want I would try something like this
from PIL import Image
picture = Image.open("/path/to/my/picture.jpg")
# Get the size of the image
width, height = picture.size()
# Process every pixel
for x in width:
for y in height:
current_color = picture.getpixel( (x,y) )
####################################################################
# Do your logic here and create a new (R,G,B) tuple called new_color
####################################################################
picture.putpixel( (x,y), new_color)
Change pixel colors between two different colors
We may start the solution by using cv2.floodFill method.
Main stages:
- Fill the lower part with black using
floodFill
(assume only yellow and green pixels). - Fill the top part with black using
floodFill
(assume only red and green pixels). - Find pixels where both top and bottom are zeros (black).
- Replace the pixels that are both black with red color.
Code sample:
import cv2
import numpy as np
img = cv2.imread('red_yellow_green.jpg')
cols, rows = img.shape[0], img.shape[1]
red = img[0, 0, :].tolist() # Get the red color from the top left corner
# Make the green a "true green"
img2 = img.copy()
green_ch = img2[:, :, 1]
green_ch[green_ch > 100] = 255
# Fill the lower part with black (assume only yellow and green pixels)
bot_black = img2
cv2.floodFill(bot_black, None, seedPoint=(rows-1, cols-1), newVal=(0, 0, 0), loDiff=(255, 20, 255), upDiff=(255, 20, 255))
# Fill the top part with black (assume only red and green pixels)
top_black = img.copy()
cv2.floodFill(top_black, None, seedPoint=(0, 0), newVal=(0, 0, 0), loDiff=(50, 255, 50), upDiff=(50, 255, 50))
# Find pixels where both top and bottom are zeros
both_black = np.logical_and(np.all(bot_black[:, :, 0:3] == (0, 0, 0), 2), np.all(top_black[:, :, 0:3] == (0, 0, 0), 2))
# Convert to uint8 and dilate (this part is just for aesthetics).
both_black = both_black.astype(np.uint8)*255
both_black = cv2.dilate(both_black, np.ones((5,5)))
# Replace the pixels that are both black with red color
img[both_black == 255] = red
# Show images for testing:
cv2.imshow('bot_black', bot_black)
cv2.imshow('top_black', top_black)
cv2.imshow('both_black', both_black)
cv2.imshow('img', img)
cv2.waitKey()
cv2.destroyAllWindows()
Results:
bot_black
:
top_black
:
both_black
:
img
:
The above solution is not the most general solution.
There is also an option to find all the green contours, create a mask of the contours perimeter, and analyze the colors of the perimeter of each contour (and fill contours with mixed perimeter colors with red color).
How to change the set of pixel colors in contatc with black color
Please, post lossless versions of your input images. Lossy images modify the value of the pixels, creating artifacts that affect processing. I recreated your image and saved it as a lossless PNF file.
I'm using OpenCV to get the result you want. I created a mask with the non-zero elements of your original input. Then, I used Flood-fill to fill the outer shapes with the color you want. The final image can be obtained if you AND
both images.
Let's see the code:
# import opencv:
import cv2
# image path
path = "D://opencvImages//"
fileName = "rectsLossless.png"
# Reading an image in default mode:
inputImage = cv2.imread(path + fileName)
# Grayscale image:
grayscaleImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
# Get non-zero mask:
binaryThresh = 1
_, binaryMask = cv2.threshold(grayscaleImage, binaryThresh, 255, cv2.THRESH_BINARY)
This bit creates the non-zero pixels mask:

This will help to zero all the elements that are non-white. That image is the first part of the mask. Now, let's fill the outer shapes with red color. This is achieved in three steps:
# Get image dimensions:
(imageHeight, imageWidth) = inputImage.shape[:2]
# Get image center:
xCenter = int(0.5 * imageWidth)
yCenter = int(0.5 * imageHeight)
# Get flood-fill target color
floodColor = inputImage[yCenter, xCenter]
print("Flood Color: %s" % floodColor)
# numpy array to tuple
floodColor = (int(floodColor[0]), int(floodColor[1]), int(floodColor[2]))
The first step gets the actual filling color. I suppose that the red is located more or less at the center of the image. Then, the second step involves filling all the "foreground" pixels with white. Let's seed at the top left corner:
# Flood fill at top left corner:
leftCorner = (1, 1)
whiteColor = (255, 255, 255)
cv2.floodFill(inputImage, None, leftCorner, whiteColor)
This is the result:

Note how the shapes that are partially outside of the red rectangle are all now connected by the white color. Let's fill again, but this time using the red color I extracted previously:
# Second Flood-fill
cv2.floodFill(inputImage, None, leftCorner, floodColor)
This yields the following image:

Let's create the final image by AND
ing this result with the original non-zero mask:
# Create final image:
outImage = cv2.bitwise_and(inputImage, inputImage, mask=binaryMask)
This is the final result:

How to change the color of a pixel using PIL?
Is using PIL
a must in your case? If not then consider using OpenCV (cv2
) for altering particular pixels of image.
Code which alter (0,0) pixel to (200,200,200) looks following way in opencv:
import cv2
img = cv2.imread('yourimage.jpg')
height = img.shape[0]
width = img.shape[1]
img[0][0] = [200,200,200]
cv2.imwrite('newimage.bmp',img)
Note that this code saves image in .bmp
format - cv2 can also write .jpg
images, but as jpg is generally lossy format, some small details might be lost. Keep in mind that in cv2
[0][0]
is left upper corner and first value is y-coordinate of pixel, while second is x-coordinate, additionally color are three values from 0
to 255
(inclusive) in BGR
order rather than RGB
.
For OpenCV tutorials, including installation see this.
Customize (change) image (pixel) colours - python
I'm not familiar with PIL, and I heard that it's slow. So here's a OpenCV version:
# for red color, it's easier to work with negative image
# since hue is in [170, 180] or [0,10]
hsv_inv = cv2.cvtColor(255-img, cv2.COLOR_BGR2HSV)
# these are cyan limit, but we're working on negative image, so...
lower_range = np.array([80,0,0])
upper_range = np.array([100,255,255])
# mask the red
mask = cv2.inRange(hsv_inv, lower_range, upper_range)
# replace red by green
green_hsv = hsv_inv.copy()
green_hsv[np.where(mask)] += np.array([60,0,0], dtype=np.uint8)
green_img = 255 - cv2.cvtColor(green_hsv, cv2.COLOR_HSV2BGR)
purple_hsv = hsv_inv.copy()
purple_hsv[np.where(mask)] -= np.array([30,0,0], dtype=np.uint8)
purple_img = 255 - cv2.cvtColor(purple_hsv, cv2.COLOR_HSV2BGR)
And result, pls ignore the ticks as I showed them by matplotlib.
How to change the colour of pixels in an image depending on their initial luminosity?
There are many ways to do this, but the simplest and probably fastest is with Numpy, which you should get accustomed to using with image processing in Python:
from PIL import Image
import numpy as np
# Load image and ensure RGB, not palette image
im = Image.open('start.png').convert('RGB')
# Make into Numpy array
na = np.array(im)
# Make all pixels of "na" where the mean of the R,G,B channels is less than 50 into black (0)
na[np.mean(na, axis=-1)<50] = 0
# Convert back to PIL Image to save or display
result = Image.fromarray(na)
result.show()
That turns this:
Into this:
Another slightly different way would be to convert the image to a more conventional greyscale, rather than averaging for the luminosity:
# Load image and ensure RGB
im = Image.open('start.png').convert('RGB')
# Calculate greyscale version
grey = im.convert('L')
# Point process over pixels to make mask of darker ones
mask = grey.point(lambda p: 255 if p<50 else 0)
# Paste black (i.e. 0) into image where mask indicates it is dark
im.paste(0, mask=mask)
Notice that the blue channel is given considerably less significance in the ITU-R 601-2 luma transform that PIL uses (see the lower 114 weighting for Blue versus 299 for Red and 587 for Green) in the formula:
L = R * 299/1000 + G * 587/1000 + B * 114/1000
so the blue shades are considered darker and become black.
Another way would be to make a greyscale and a mask as above. but then choose the darker pixel at each location when comparing the original and the mask:
from PIL import Image, ImageChops
im = Image.open('start.png').convert('RGB')
grey = im.convert('L')
mask = grey.point(lambda p: 0 if p<50 else 255)
res = ImageChops.darker(im, mask.convert('RGB'))
That gives the same result as above.
Another way, pure PIL and probably closest to what you actually asked, would be to derive a luminosity value by averaging the channels:
# Load image and ensure RGB
im = Image.open('start.png').convert('RGB')
# Calculate greyscale version by averaging R,G and B
grey = im.convert('L', matrix=(0.333, 0.333, 0.333, 0))
# Point process over pixels to make mask of darker ones
mask = grey.point(lambda p: 255 if p<50 else 0)
# Paste black (i.e. 0) into image where mask indicates it is dark
im.paste(0, mask=mask)
Another approach could be to split the image into its constituent RGB channels, evaluate a mathematical function over the channels and mask with the result:
from PIL import Image, ImageMath
# Load image and ensure RGB
im = Image.open('start.png').convert('RGB')
# Split into RGB channels
(R, G, B) = im.split()
# Evaluate mathematical function over channels
dark = ImageMath.eval('(((R+G+B)/3) <= 50) * 255', R=R, G=G, B=B)
# Paste black (i.e. 0) into image where mask indicates it is dark
im.paste(0, mask=dark)
Related Topics
Cv2.Videocapture.Open() Always Returns False
How to Track the Number of Times a Function Is Called
Python Pandas Count the Number of Occurances Inside Lists in a Column
How to Get Local Issuer Certificate When Using Requests in Python
No Matching Distribution Found for Tkinter
Pyspark Data Frame Converting False and True to 0 and 1
Algorithm for Distributing a Number Between Certain Number of Chunks
Python Opencv Cv2 - How to Increase the Brightness and Contrast of an Image by 100%
How to Remove Grid Lines on Image in Python
Formatting Datetimefield in Django
How to Append Data Using Openpyxl Python to Excel File from a Specified Row
Generate List of Quarters Betweeen Given Dates
How to Convert Signed to Unsigned Integer in Python
How to Get Python to Detect for No Input
Python: Using Doctests for Classes
How to Convert a Pandas Dataframe to a Pytorch Tensor