Can anyone see where I'm going wrong? I've been through it line by line and it all produces expected results up until new_face, when new_face starts producing NoneType's.
import numpy, cv2
from PIL import Image
face_cascade = cv2.CascadeClassifier("..data/haarcascade_frontalface_default.xml") #absolute path cut down for privacy
def find_faces(image_for_faces):
image = image_for_faces.resize((1800,3150))
image_np = numpy.asarray(image)
image_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(image_gray) #correct numpy array, prints correct coordinates per face
face_list = []
image.show()
for face in faces:
print(face)
box = (face[0], face[1], face[0]+face[2], face[1]+face[3]) #correctly produces numpy coordinates
copy_image = image.copy()
cropped = copy_image.crop(box = (box))
new_face = cropped.thumbnail((128,128))
face_list.append(new_face)
return face_list
y = Image.open('famphoto.jpg')
z = y.convert('RGB')
x = find_faces(z)
The Image.thumbnail() modifies the Image object in place, read more about it in the docs. It mentions that it returns a None type.
Image.thumbnail:
Make this image into a thumbnail. This method modifies the image to
contain a thumbnail version of itself, no larger than the given size.
This method calculates an appropriate thumbnail size to preserve the
aspect of the image, calls the draft() method to configure the file
reader (where applicable), and finally resizes the image.
Related
Whenever I convert a PNG image to a np.array and then convert it back to a PNG I lose all the colors of the image. I would like to be able to retain the colors of the original PNG when I am converting it back from a np.array.
Original PNG Image
My code:
from PIL import Image
im = Image.open('2007_000129.png')
im = np.array(im)
#augmenting image
im[0,0] = 1
im = Image.fromarray(im, mode = 'P')
Outputs a black and white version of the image
I also try using getpalette and putpalette but this does not work it just returns a NonType object.
im = Image.open('2007_000129.png')
pat = im.getpalette()
im = np.array(im)
im[0,0] = 1
im = Image.fromarray(im, mode = 'P')
im= im.putpalette(pat)
Your image is using single channel color using palette. Try the code below. Also you can check more about this subject at What is the difference between images in 'P' and 'L' mode in PIL?
from PIL import Image
import numpy as np
im = Image.open('gsmur.png')
rgb = im.convert('RGB')
np_rgb = np.array(rgb)
p = im.convert('P')
np_p = np.array(p)
im = Image.fromarray(np_p, mode = 'P')
im.show()
im2 = Image.fromarray(np_rgb)
im2.show()
Using the second code provided, the error comes from this line:
im= im.putpalette(pat)
If you refer to the documentation of Image.putpalette, you see that this function doesn't return any value, thus Image.putpalette is applied to the corresponding image directly. So, (re-)assigning the non-existent return value (which then is None) is not necessary – or, as seen here, erroneous.
So, the simple fix is just to use:
im.putpalette(pat)
Using this change, the second code provided works as intended.
I am making a program where you can chose an image and a color and it will invert only the pixels that match that color. I've been surfing stackoverflow and reddit for solutions but so far no luck.
I tried to do something like this first:
img = Image.open('past.png')
pixels = img.load()
for i in goodpixels:
ImageOps.invert(pixels[i])
AttributeError: 'tuple' object has no attribute 'mode'
No luck with that because ImageOps.invert only inverts full images. Next I tried to use ImageOps.polarize but realized that I couldn't use it because it takes greyscale thresholds not rgb values.
img = Image.open('past.png')
pixels = img.load()
for i in goodpixels:
ImageOps.solarize(img, threshold=pixels[i])
TypeError: '<' not supported between instances of 'int' and 'tuple'
This is my issue, I don't know if this is even possible. If it takes too much work I will probably abandon the project anyways because I'm just keeping myself occupied, and this isn't for marks/job.
Some more code:
def checkpixels():
img = Image.open('past.png')
height, width = img.size
img = img.convert('RGB')
targetcolor = input('What color do you want to search for, you can use RGB format or common names like \'red\', \'black\', e.t.c. Leave this blank to invert all pixels. ')
print('Processing image. This could take several minutes.')
isrgb = re.match(r'\d+, \d+, \d+|\(\d+, \d+, \d+\)', targetcolor)
if type(isrgb) == re.Match:
targetcolor = targetcolor.strip('()')
targetcolor = targetcolor.split(', ')
targetcolor = tuple(map(int, targetcolor))
print(str(targetcolor))
for x in range(width):
for y in range(height):
color = img.getpixel((y-1, x-1))
if color == targetcolor:
goodpixels.append((y-1, x-1))
else:
try:
targetcolor = ImageColor.getcolor(targetcolor.lower(), 'RGB')
print(targetcolor)
for x in range(width):
for y in range(height):
color = img.getpixel((y-1, x-1))
if color == targetcolor:
goodpixels.append((y-1, x-1))
except:
print('Not a valid color smh.')
return goodpixels
goodpixels = []
goodpixels = checkpixels()
Edit: I figured it out! Thank you to Mark Setchell for his incredible brain! I ended up using numpy to convert the image and target color to arrays, making an inverted copy of the image, and using numpy.where() to decide whether or not to switch out the pixels. I also plan on making the target color a range so the chosen color doesn't have to be so specific. All in all my code looks like this:
goodpixels = []
targetcolor = inputcolor()
img = Image.open('past.png')
invertimage = img.copy().convert('RGB')
invertimage = ImageOps.invert(invertimage)
invertimage.save('invert.png')
pastarray = np.array(img)
targetcolorarray = np.array(targetcolor)
pixels = img.load()
inverse = np.array(invertimage)
result = np.where((pastarray==targetcolorarray).all(axis=-1)[...,None], inverse, pastarray)
Image.fromarray(result.astype(np.uint8)).save('result.png')
Of course, inputcolor() is a function offscreen which just decides if the input is a color name or rgb value. Also I used import numpy as np in this example.
A problem that I had was that original my .where method looked like this:
result = np.where((pastarray==[0, 0, 0]).all(axis=-1)[...,None], inverse, pastarray)
This brought up the error: AttributeError: 'bool' object has no attribute 'all'
It turns out all I had to do was convert my color into an array!
Many libraries allow you to import an image into Python as a numpy array. PIL or opencv2 are well documented libraries for working with images:
pip install opencv2
Example numpy.where() selection, meeting a set criteria, in this case inverting all pixel values below THRESHOLD:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# cut off thereshold
THRESHOLD = 230
pixel_data = cv2.imread('filename.png')
pixel_data = np.where(pixel_data < THRESHOLD, 1/pixel_data, pixel_data)
# display the edited image using matplotlib
plt.imshow(pixel_data)
The numpy.where() function applies a condition to your numpy array. More details available on the: numpy official documentation
I'm trying to convert a 1-layer (grey-scale) image to a 3-layer RGB image. Below is the code I'm using. This runs without error but doesn't create the correct result.
from PIL import Image # used for loading images
def convertLToRgb(img):
height = img.size[1]
width = img.size[0]
size = img.size
mode = 'RGB'
data = np.zeros((height, width, 3))
for i in range(height):
for j in range(width):
pixel = img.getpixel((j, i))
data[i][j][0] = pixel
data[i][j][1] = pixel
data[i][j][2] = pixel
img = Image.frombuffer(mode, size, data)
return img
What am I doing wrong here? I'm not expecting a color picture, but I am expecting a black and white picture resembling the input. Below are the input and output images:
Depending on the bit depth of your image, change:
data = np.zeros((height, width, 3))
to:
data = np.zeros((height, width, 3), dtype=np.uint8)
For an 8-bit image, you need to force your Numpy array dtype to an unsigned 8-bit integer, otherwise it defaults to float64. For 16-bit, use np.uint16, etc.
What is your task? black-white image or RGB color image. If you want to convert the gray image to the black-white image. You can directly convert the image into a binary image. As for your code, two things you need to care. Firstly, the location of the pixel is right, the wrong location will make the image all black like your post. Secondly, you only can convert the RGB to grayscale image directly, but you can not convert the grayscale image to RGB directly, because it may be not accurate.
You can do it with the PIL.Image and PIL.ImageOps as shown below. Because of the way it's written, the source image isn't required to be one layer—it will convert it to one if necessary before using it:
from PIL import Image
from PIL.ImageOps import grayscale
def convertLToRgb(src):
src.load()
band = src if Image.getmodebands(src.mode) == 1 else grayscale(src)
return Image.merge('RGB', (band, band, band))
src = 'whale_tail.png'
bw_img = Image.open(src)
rgb_img = convertLToRgb(bw_img)
rgb_img.show()
i am trying to recreate a picture. I take a picture edging it and save it. after i made it grayscale and save it. Found the common pixels of the two images and I am trying to recreate again the picture and i get this error. It is a picture of a road and i am trying to keep only the white lanes. so after i compare the edged picture with the first picture most common pixels are the white ones that represent the lanes of the road.
The error is thrown in line marked <———-- near the end of the code listing
TypeError: too many data entries
newpic is the list in that form `[1,1,1,1,...,1]
here is my code and explaining every part. if you have any other suggestion how to achieve the result i want please say it
#LIBRARIES
import cv2
import numpy as np
import matplotlib as mpl
from matplotlib import pyplot as plt
#read and display the image
img = cv2.imread("road.jpg")
#original picture show
cv2.imshow("Window Name",img)
# edging the image
edges = cv2.Canny(img,255,255)
#show the canny picture
cv2.imshow("Window Name",edges)
#save the canny picture First argument is the file name, second
argument is the image you want to save.
cv2.imwrite('canny.png',edges)
#making the image an array
from PIL import Image
#read the pciture
img = Image.open('road.jpg').convert('LA')
#save it
img.save('greyscale.png')
#open the edited
im=Image.open("greyscale.png")
#make it an array
pix_val = list(im.getdata())
pix_val_flat = [x for sets in pix_val for x in sets]
# pix_val_flat has the pixels for out first image without edging
#print the array
#print (pix_val_flat[125]);
#get the lenght of the array
lenght=len(pix_val_flat)
#print the array
#print(lenght);
#take the canny picture and make it grayscale
edge = Image.open('canny.png').convert('LA')
#make it array
pix_val1 = list(edge.getdata())
pix_val_flat1 = [x for sets in pix_val for x in sets]
#get the lenght of the array
#lenght1=len(pix_val_flat1)
#prnt the array
#print(lenght);
#print the array
#print (pix_val_flat1[125]);
print(lenght)
newpic = [0]*lenght
lenght2=len(newpic)
print (newpic)
for c1 in range(0,lenght,3):
if pix_val_flat[c1]==pix_val_flat1[c1] and
pix_val_flat[c1+1]==pix_val_flat1[c1+1] and
pix_val_flat[c1+2]==pix_val_flat1[c1+2]:
newpic[c1]= pix_val_flat1[c1]
newpic[c1+1]= pix_val_flat1[c1+1]
newpic[c1+2]= pix_val_flat1[c1+2]
array = np.array(newpic, dtype=np.uint8)
print (array)
im2 = Image.new(im.mode, im.size)
im2.putdata (newpic) ---------------------> here i get the error
new_image = Image.fromarray(array)
new_image.save('hello.png')
cv2.waitKey(0)
cv2.destroyAllWindows()
In this case it means that your putting more data than the size you set before.
You can check the length of data you put in with len(the_list_of_data), so you'll see length gets double every time you put data (even if you overwrite). You can set the_list_of_data length to 0 and then fill it with data. This error occurs in loops too.
I am loading my Image file using Image.open("image.tif"). Then i am using Image.load() to generate a pixelMap of the image. Then i am storing each pixel into an array. The following code describes this process. Then I want to create the ascii value of each pixel and store it in a string. So I going through each pixel in my pixel array and then change the pixel value to ascii value. However I am having an error because I am getting some pixel values greater than 250. How is this possible. Also, it is b/w image. What am I doing wrong?
self.filename = filename
self.im = Image.open(filename)
self.pixelmap = self.im.load() #Loads the image as a map of pixels
self.arr = []
for i in range(self.im.size[0]):
for j in range(self.im.size[1]):
mypixel = self.pixelmap[i, j]
self.arr.append(mypixel)
for i in msgFile.arr:
self.message += str(unichr(int(i)))
something like this?
from PIL import Image
import numpy as np
image = np.asarray(Image.open('image.jpg'))
_y, _x, _z = image.shape
str_array = [str(image[y][x]) for y in range(_y) for x in range(_x)]