Changing pixel color Python - python

I am suppose to get an image from my fluke robot and determine the color of each pixel in my image. Then if the pixel is mostly red, change it to completely green. If the pixel is mostly green, change it to completely blue. If the pixel is mostly blue, change it to completely red. This is what I am able to do, but I can't get it to work to get the image I have to change. There is no syntax error, it is just semantic I am having trouble with. I am using python.
My attempted code:
import getpixel
getpixel.enable(im)
r, g, b = im.getpixel(0,0)
print 'Red: %s, Green:%s, Blue:%s' % (r,g,b)
Also I have the picture saved like the following:
pic1 = makePicture("pic1.jpg"):
for pixel in getpixel("pic1.jpg"):
if pixel Red: %s:
return Green:%s
if pixel Green:%s:
return Blue:%s

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)

You have mistakes:
# Get the size of the image
width, height = picture.size()
for x in range(0, width - 1):
for y in range(0, height - 1):
Brackets are mistake!! omit them.
int is not iterable.
I also recommend you to use load(), because it's much faster :
pix = im.load()
print pix[x, y]
pix[x, y] = value

I'm using python 3.6.4 and Pillow 5.0.0. Gizmo's code snippet didn't work for me. After little work I created a fixed snippet:
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 range(width):
for y in range(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)

import cv2
import numpy as np
m = cv2.imread("C:/../Sample Pictures/yourImage.jpg")
h,w,bpp = np.shape(m)
for py in range(0,h):
for px in range(0,w):
#can change the below logic of rgb according to requirements. In this
#white background is changed to #e8e8e8 corresponding to 232,232,232
#intensity, red color of the image is retained.
if(m[py][px][0] >200):
m[py][px][0]=232
m[py][px][1]=232
m[py][px][2]=232
cv2.imshow('matrix', m)
cv2.waitKey(0)
cv2.imwrite('yourNewImage.jpg',m)

Adding some remarks on Gizmo's answer. This:
px = im.load()
current_color = (px[i, j])
is probably faster than this:
picture.getpixel( (x,y) )
Also, make sure to use this:
picture.putdata(colors)
instead of this inside the loop:
picture.putpixel( (x,y), new_color)

Change color of pixel on picture Меняем цвет пикселя в картинке(меняем фон)
https://colorscheme.ru/color-converter.html¶
Find one color on picture and change На всей картинке находит цвет и заменяет его другим.
import numpy as np
from PIL
import Image
import os,sys
im = Image.open('1.png')
data = np.array(im)
#Original value(цвет который будем менять)
r1, g1, b1 = 90, 227, 129
#Value that we want to replace it with(цвет выхода)
r2, g2, b2 = 140, 255, 251
red, green, blue = data[:,:,0], data[:,:,1], data[:,:,2]
mask = (red == r1) & (green == g1) & (blue == b1)
data[:,:,:3][mask] = [r2, g2, b2]
im = Image.fromarray(data)
im.save('1_mod.png')

Related

Replace all the color of each pixel using PIL (currently replacing specific color

I'm trying to replace a color range with some specific color using PIL module.
Suppose I want to change the color of the sky,I need to generate a list of the color of pixels.
My code currently
from PIL import Image, ImageColor
im = Image.open("iphone.jpg", "r")
to_be_replaced = ImageColor.getcolor("#5f86c9", "RGB")
newcolor = ImageColor.getcolor("#c9bb5f", "RGB")
print(to_be_replaced, newcolor)
pix = im.load()
width, height = im.size
for w in range(width):
for h in range(height):
r, g, b = pix[(w, h)]
if (r, g, b) == to_be_replaced:
pix[w, h] = newcolor
else:
pix[w, h] = (r, g, b)
im.save('test.png', 'PNG')
newcolor here is the yellow color, and to_be_replaced is the color of a pixel from the sky.
Code output till now:
The script works, but currently, it changes the color of just a pixel with the specified color. I want to replace the color of the whole sky. Can anybody please help me with this problem?

Finding the "level of black" in a pixel in a grayscale image

I am trying to calculate the percentage of black a pixel is. For example, let's say I have a pixel that is 75% black, so a gray. I have the RGBA values, so how do I get the level of black?
I have already completed getting each pixel and replacing it with a new RGBA value, and tried to use some RGBA logic to no avail.
#Gradient Testing here
from PIL import Image
picture = Image.open("img1.png")
img = Image.open('img1.png').convert('LA')
img.save('greyscale.png')
# Get the size of the image
width, height = picture.size
# Process every pixel
for x in range(width):
for y in range(height):
#Code I need here
r1, g1, b1, alpha = picture.getpixel( (x,y) )
r,g,b = 120, 140, 99
greylvl = 1 - (alpha(r1 + g1 + b1) / 765) #Code I tried
I would like to get new variable called that gives me a value, such as 0.75, which would represent a 0.75 percent black pixel.
I'm not quite sure what the "LA" format you're trying to convert to is for; I would try "L" instead.
Try this code: (Make sure you're using Python 3.)
from PIL import Image
picture = Image.open('img1.png').convert('L')
width, height = picture.size
for x in range(width):
for y in range(height):
value = picture.getpixel( (x, y) )
black_level = 1 - value / 255
print('Level of black at ({}, {}): {} %'.format(x, y, black_level * 100))
Is this what you're looking for?

How to remove unwanted parts in an image and then create a new small image using Python?

I want to remove the dark(black strips) and also the white curves in the image, and then align the remained parts connected in a new small-sized image, making the colored parts looks continuously. I hope can get some suggestions for solutions.
I have tried to use PIL to read the image.
I don't know how to set the right threshold and resize the image
I'm not an expert at all in image processing, but let me know if this is enough for you.
Looking at the brightness (sum of the RGB values) distribution, maybe one option is to just filter pixel based on their value:
It looks like the dark parts have a brightness below 100 (or something like that). I filtered it this way:
from PIL import Image
import numpy as np
def filter_image(img,threshold=100):
data = np.array(img.convert('RGB'))
brightness = np.sum(data,axis=2)
filtered_img = data.copy()*0
for i in range(data.shape[0]):
k = 0 # k index the columns that are bright enough
for j in range(data.shape[1]):
if brightness[i,j] > threshold:
filtered_img[i,k,:] = data[i,j,:]
k += 1 # we increment only if it's bright enough
# End of column iterator. The right side of the image is black
return Image.fromarray(filtered_img)
img = Image.open("test.png")
filtered = filter_image(img)
filtered.show()
I get the following result. I'm sure experts can do much better, but it's a start:
The following is only looking for black pixels, as can be seen by the first image, many of the pixels you want out are not black. You will need to find a way to scale up what you will take out.
Also, research will need to be done on collapsing an image, as can be seen by my collapse. Although, this image collapse may work if you are able to get rid of everything but the reddish colors. Or you can reduce by width, which is what the third picture shows.
from PIL import Image, ImageDraw
def main():
picture = Image.open('/Volumes/Flashdrive/Stack_OverFlow/imageprocessing.png', 'r')
# pix_val = list(im.getdata())
# print(pix_val)
# https://code-maven.com/create-images-with-python-pil-pillowimg = Image.new('RGB', (100, 30), color = (73, 109, 137))
blackcount = 0
pix = picture.convert('RGB') # https://stackoverflow.com/questions/11064786/get-pixels-rgb-using-pil
width, height = picture.size
img = Image.new('RGB', (width, height), color=(73, 109, 137))
newpic = []
for i in range(width):
newpictemp = []
for j in range(height):
# https://stackoverflow.com/questions/13167269/changing-pixel-color-python
r, g, b = pix.getpixel((i, j))
if r == 0 and g == 0 and b == 0:
blackcount += 1
else:
img.putpixel((i, j), (r, g, b))
newpictemp.append((r, g, b))
newpic.append(newpictemp)
img.save('pil_text.png')
newheight = int(((width * height) - blackcount) / width)
print(newheight)
img2 = Image.new('RGB', (width, newheight), color=(73, 109, 137))
for i in range(width):
for j in range(newheight):
try:
z = newpic[i][j]
img2.putpixel((i, j), newpic[i][j])
except:
continue
img2.save('pil_text2.png')
if __name__ == "__main__":
main()
No black pixels on left, removed black pixels on right, remove and resize by width (height resize shown in code)

Can't figure out how to have everything compile and return my image

Can't figure out how to have everything compile and return my image.
from PIL import Image
def open_bird():
filename = 'bird_scrambled.png' #Call File
picture = Image.open(filename) #Opens file for use
return(picture)
def unscramble_left(picture):
width, height = picture.size #Call image size, log
for x in range (0, (width/2)): # width is /2
for y in range (0, height): # height remains same
red, green, blue = picture.getpixel((x,y)) # call pixels in x,y grid
picture.putpixel((x,y), (blue,green,red)) # replace pixels rgb -> bgr
return(picture)
def unscramble_top(picture):
width, height = picture.size
for x in range (0, (width/2)):
for y in range (0, (height/2)):
red, green, blue = picture.getpixel((x,y))
for red in picture:
if red >= 127:
red = red - 127
else:
red = red + 127
picture.show()
def put_together():
open_bird()
unscramble_left(picture)
unscramble_top(picture)
So basically, I want to return the picture from each function after it's be set in the initial function. Passing the photo through unscramble_left(), to unscramble_top; and finally having it compile in a final function of put_together(). Every time I try running this though, I end up with the issue of the return value Picture not coming through in the final put_together function. I'm doing the final function as it all needs to be called from one function. So that's my issue. It's just not returning.
I am not entirely sure what you are trying to accomplish, but the code at least compiles now. I ended up editing a few things:
It seems like your put together function was an attempt to be the function which gets run, when the program starts. Therefore it turned it into main.
I it seemed like you were trying to pass around the picture, so I changed it to do actually do so.
In addition, I edited the range of several for loops. Given that the range must be from an integer to another integer, I added rounding. Currently it uses ceil() to round the value up, but you may want to use floor() to round the value down
It seemed like you were trying to edit each pixel in unscramble_top. So I edited it to do so. Originally, you had it so that it was trying to iterate though the pixel, which will not work because each individual pizel has only one value for r, one for g, and one for b.
Code
from PIL import Image
from math import ceil
def open_bird():
filename = 'Image.jpeg' # Call File
picture = Image.open(filename) # Opens file for use
return picture
def unscramble_left(picture):
width, height = picture.size # Call image size, log
for x in range(0, ceil(width / 2)): # width is /2
for y in range(0, height): # height remains same
red, green, blue = picture.getpixel((x, y)) # call pixels in x,y grid
picture.putpixel((x, y), (blue, green, red)) # replace pixels rgb -> bgr
return picture
def unscramble_top(picture):
width, height = picture.size
for x in range(0, ceil(width / 2)):
for y in range(0, ceil(height / 2)):
red, green, blue = picture.getpixel((x, y))
if red >= 127:
red = red - 127
else:
red = red + 127
return picture
def main():
picture = open_bird()
picture = unscramble_left(picture)
picture = unscramble_top(picture)
picture.show()
if __name__ == '__main__':
main()

PIL Best Way To Replace Color?

I am trying to remove a certain color from my image however it's not working as well as I'd hoped. I tried to do the same thing as seen here Using PIL to make all white pixels transparent? however the image quality is a bit lossy so it leaves a little ghost of odd colored pixels around where what was removed. I tried doing something like change pixel if all three values are below 100 but because the image was poor quality the surrounding pixels weren't even black.
Does anyone know of a better way with PIL in Python to replace a color and anything surrounding it? This is probably the only sure fire way I can think of to remove the objects completely however I can't think of a way to do this.
The picture has a white background and text that is black. Let's just say I want to remove the text entirely from the image without leaving any artifacts behind.
Would really appreciate someone's help! Thanks
The best way to do it is to use the "color to alpha" algorithm used in Gimp to replace a color. It will work perfectly in your case. I reimplemented this algorithm using PIL for an open source python photo processor phatch. You can find the full implementation here. This a pure PIL implementation and it doesn't have other dependences. You can copy the function code and use it. Here is a sample using Gimp:
to
You can apply the color_to_alpha function on the image using black as the color. Then paste the image on a different background color to do the replacement.
By the way, this implementation uses the ImageMath module in PIL. It is much more efficient than accessing pixels using getdata.
EDIT: Here is the full code:
from PIL import Image, ImageMath
def difference1(source, color):
"""When source is bigger than color"""
return (source - color) / (255.0 - color)
def difference2(source, color):
"""When color is bigger than source"""
return (color - source) / color
def color_to_alpha(image, color=None):
image = image.convert('RGBA')
width, height = image.size
color = map(float, color)
img_bands = [band.convert("F") for band in image.split()]
# Find the maximum difference rate between source and color. I had to use two
# difference functions because ImageMath.eval only evaluates the expression
# once.
alpha = ImageMath.eval(
"""float(
max(
max(
max(
difference1(red_band, cred_band),
difference1(green_band, cgreen_band)
),
difference1(blue_band, cblue_band)
),
max(
max(
difference2(red_band, cred_band),
difference2(green_band, cgreen_band)
),
difference2(blue_band, cblue_band)
)
)
)""",
difference1=difference1,
difference2=difference2,
red_band = img_bands[0],
green_band = img_bands[1],
blue_band = img_bands[2],
cred_band = color[0],
cgreen_band = color[1],
cblue_band = color[2]
)
# Calculate the new image colors after the removal of the selected color
new_bands = [
ImageMath.eval(
"convert((image - color) / alpha + color, 'L')",
image = img_bands[i],
color = color[i],
alpha = alpha
)
for i in xrange(3)
]
# Add the new alpha band
new_bands.append(ImageMath.eval(
"convert(alpha_band * alpha, 'L')",
alpha = alpha,
alpha_band = img_bands[3]
))
return Image.merge('RGBA', new_bands)
image = color_to_alpha(image, (0, 0, 0, 255))
background = Image.new('RGB', image.size, (255, 255, 255))
background.paste(image.convert('RGB'), mask=image)
Using numpy and PIL:
This loads the image into a numpy array of shape (W,H,3), where W is the
width and H is the height. The third axis of the array represents the 3 color
channels, R,G,B.
import Image
import numpy as np
orig_color = (255,255,255)
replacement_color = (0,0,0)
img = Image.open(filename).convert('RGB')
data = np.array(img)
data[(data == orig_color).all(axis = -1)] = replacement_color
img2 = Image.fromarray(data, mode='RGB')
img2.show()
Since orig_color is a tuple of length 3, and data has
shape (W,H,3), NumPy
broadcasts
orig_color to an array of shape (W,H,3) to perform the comparison data ==
orig_color. The result in a boolean array of shape (W,H,3).
(data == orig_color).all(axis = -1) is a boolean array of shape (W,H) which
is True wherever the RGB color in data is original_color.
#!/usr/bin/python
from PIL import Image
import sys
img = Image.open(sys.argv[1])
img = img.convert("RGBA")
pixdata = img.load()
# Clean the background noise, if color != white, then set to black.
# change with your color
for y in xrange(img.size[1]):
for x in xrange(img.size[0]):
if pixdata[x, y] == (255, 255, 255, 255):
pixdata[x, y] = (0, 0, 0, 255)
You'll need to represent the image as a 2-dimensional array. This means either making a list of lists of pixels, or viewing the 1-dimensional array as a 2d one with some clever math. Then, for each pixel that is targeted, you'll need to find all surrounding pixels. You could do this with a python generator thus:
def targets(x,y):
yield (x,y) # Center
yield (x+1,y) # Left
yield (x-1,y) # Right
yield (x,y+1) # Above
yield (x,y-1) # Below
yield (x+1,y+1) # Above and to the right
yield (x+1,y-1) # Below and to the right
yield (x-1,y+1) # Above and to the left
yield (x-1,y-1) # Below and to the left
So, you would use it like this:
for x in range(width):
for y in range(height):
px = pixels[x][y]
if px[0] == 255 and px[1] == 255 and px[2] == 255:
for i,j in targets(x,y):
newpixels[i][j] = replacementColor
If the pixels are not easily identifiable e.g you say (r < 100 and g < 100 and b < 100) also doesn't match correctly the black region, it means you have lots of noise.
Best way would be to identify a region and fill it with color you want, you can identify the region manually or may be by edge detection e.g. http://bitecode.co.uk/2008/07/edge-detection-in-python/
or more sophisticated approach would be to use library like opencv (http://opencv.willowgarage.com/wiki/) to identify objects.
This is part of my code, the result would like:
source
target
import os
import struct
from PIL import Image
def changePNGColor(sourceFile, fromRgb, toRgb, deltaRank = 10):
fromRgb = fromRgb.replace('#', '')
toRgb = toRgb.replace('#', '')
fromColor = struct.unpack('BBB', bytes.fromhex(fromRgb))
toColor = struct.unpack('BBB', bytes.fromhex(toRgb))
img = Image.open(sourceFile)
img = img.convert("RGBA")
pixdata = img.load()
for x in range(0, img.size[0]):
for y in range(0, img.size[1]):
rdelta = pixdata[x, y][0] - fromColor[0]
gdelta = pixdata[x, y][0] - fromColor[0]
bdelta = pixdata[x, y][0] - fromColor[0]
if abs(rdelta) <= deltaRank and abs(gdelta) <= deltaRank and abs(bdelta) <= deltaRank:
pixdata[x, y] = (toColor[0] + rdelta, toColor[1] + gdelta, toColor[2] + bdelta, pixdata[x, y][3])
img.save(os.path.dirname(sourceFile) + os.sep + "changeColor" + os.path.splitext(sourceFile)[1])
if __name__ == '__main__':
changePNGColor("./ok_1.png", "#000000", "#ff0000")

Categories

Resources