I'm trying to take my HSV values and make an image out of it. Here is my code:
from __future__ import division
from PIL import Image
import numpy as np
import colorsys
fp = open('pixels.txt', 'w')
fp2 = open('hsv.txt', 'w')
im = Image.open('colorimage.png')
imrgb = im.convert("RGB")
scale = 255.0
pixels = list(imrgb.getdata())
width, height = im.size
pixels = [pixels[i * width:(i + 1) * width] for i in xrange(height)]
for pixel in pixels:
for x in pixel:
print>>fp, x
x = [x[0]/255,x[1]/255,x[2]/255]
y = colorsys.rgb_to_hsv(*x)
w = [y[0]*360, y[1]*100, y[2]*100]
h,s,v = [y[0]*360, y[1]*100, y[2]*100]
print>>fp2, w
newimg = Image.new("HSV", im.size)
print "done"
The Image.new says it takes modes: http://pillow.readthedocs.io/en/4.0.x/handbook/concepts.html#concept-modes
But it doesn't read "HSV" as a mode. It says this as the error:
Traceback (most recent call last):
File "RGBtoHIS.py", line 25, in <module>
newimg = Image.new("HSV", im.size)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PIL-1.1.7-py2.7-macosx-10.6-x86_64.egg/PIL/Image.py", line 1763, in new
return Image()._new(core.fill(mode, size, color))
ValueError: unrecognized mode
Has anyone else had this issue with the Image module?
Other:
I would like to create a Hue image and a Saturation image. Is there a way to do this with the hue and saturation values I have?
You're referencing the Pillow docs, but you're not using Pillow -- you're using the original PIL version 1.1.7, as shown by your error message:
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/
site-packages/PIL-1.1.7-py2.7-macosx-10.6-x86_64.egg/PIL/Image.py", line 1763, in new
and according to its documentation, it doesn't support HSV as a mode (see here).
Uninstall PIL, install Pillow, and then you should be able to do
In [12]: PIL.__version__
Out[12]: '3.4.2'
In [13]: Image.new("HSV", (100,100))
Out[13]: <PIL.Image.Image image mode=HSV size=100x100 at 0x7F4FA00F4F60>
Related
I'm trying to do some image processing in python.
I'm using Pillow 8.4.0 for this purpose and I need to work on individual pixels (here I'm just trying to save pixels in a text file), therefore I'm trying to use Image.load() method and looping over it but it is throwing IndexError: image index out of range
Is there a limitation in Image.load() function that is preventing me to do this?
from PIL import Image
with Image.open('nature.jpg') as img:
print("Image size is : " ,img.size)
pixels = img.load()
with open('file.txt', 'w') as file:
for row in range(img.height):
for col in range(img.width):
file.write(str(pixels[row, col])+ ' ')
file.write('\n')
Output is:
Image size is : (1024, 768)
Traceback (most recent call last):
File "main.py", line 13, in <module>
file.write(str(pixels[row, col])+ ' ')
IndexError: image index out of range
Pillow expects (x,y) rather than (y,x). Please try following:
from PIL import Image
img = Image.open('nature.jpg')
pixels = img.load()
print(pixels[img.width-1,img.height-1]) # does provide tuple describing pixel
print(pixels[img.height-1,img.width-1]) # IndexError for non-square image
I am trying to complete a challenge where i use an equation to construct a new image (d) from other images. Then i must get the flag in the image (d). The given images are a.png, b.png c.png and y.png and they can be found here: https://drive.google.com/drive/folders/1bZOm_0apr5ZmaRNf9R5UVIEmtMuYSphn?usp=sharing
The equation: d = y - 21a - 3b + 41c
My current code
from PIL import Image
imagey = Image.open('y.png')
imagea = Image.open('a.png')
imageb = Image.open('b.png')
imagec = Image.open('c.png')
size = width, height = imagey.size
new = Image.new('RGB', size)
imgy = imagey.load()
imga = imagea.load()
imgb = imageb.load()
imgc = imagec.load()
data = new.load()
for x in range(width):
for y in range(height):
they = imgy[x, y]
thea = imga[x, y]
theb = imgb[x, y]
thec = imgc[x, y]
new_color = ((int(they[0])) & ~(int((21 * thea[0])) ^ int((3 * theb[0])) ^ int(~(41 * thec[0]))),
(int(they[1])) & ~(int((21 * thea[1])) ^ int((3 * theb[1])) ^ int(~(41 * thec[1]))),
(int(they[2])) & ~(int((21 * thea[2])) ^ int((3 * theb[2])) ^ int(~(41 * thec[2]))))
data[x, y] = new_color
new.save('final.png')
new.show()
If you would convert Pillow image to numpy array or you would use OpenCV or imageio to load image (and get directly numpy array) then you could do
directly
new = imagey - 21*imagea - 3*imageb + 41*imagec
Result:
Not ideal but much better than with your code.
It can be problem with overflow. It may create array with 8bits values and calculations can gives 16bits or 32bits values which can be reduced to 8bits in every calculation.
Full working code:
import imageio
imagey = imageio.imread('y.png')
imagea = imageio.imread('a.png')
imageb = imageio.imread('b.png')
imagec = imageio.imread('c.png')
new = imagey - 21*imagea - 3*imageb + 41*imagec
imageio.imwrite('final.png', new)
# --- imageio doesn't have function to display it ---
import matplotlib.pyplot as plt
plt.imshow(new)
plt.show()
EDIT:
If I use OpenCV then I get ideal result
Full working code:
import cv2
imagey = cv2.imread('y.png')
imagea = cv2.imread('a.png')
imageb = cv2.imread('b.png')
imagec = cv2.imread('c.png')
new = imagey - 21*imagea - 3*imageb + 41*imagec
cv2.imwrite('final.png', new)
# --- show window with image and wait for press any key ---
cv2.imshow('Image', new)
cv2.waitKey(0)
cv2.destroyAllWindows()
EDIT:
By the way: version which converts PIL Image to numpy array and later it converts back to PIL Image - but it gives the same result as imageio.
from PIL import Image
import numpy as np
imagey = Image.open('y.png')
imagea = Image.open('a.png')
imageb = Image.open('b.png')
imagec = Image.open('c.png')
arr_y = np.array(imagey)
arr_a = np.array(imagea)
arr_b = np.array(imageb)
arr_c = np.array(imagec)
arr_new = arr_y - 21*arr_a - 3*arr_b + 41*arr_c
new = Image.fromarray(arr_new)
new.save('final.png')
new.show()
BTW:
If I check images on Linux using program file then it shows that b.png and c.png are JPEG, not PNG.
$ file b.png
b.png: JPEG image data, JFIF standard 1.01, resolution (DPI),
density 300x300, segment length 16,
Exif Standard: [TIFF image data, big-endian, direntries=0], baseline,
precision 8, 960x640, components 3
I found that cv2.imread() gives little different values for c.png(which is JPG file) then other modules - and I don't mean that cv2 gives colors in BGR instead of RGB - and later this gives correct result. Probably cv2 uses different C library to read JPG.
Can I use cv2 or numpy to turn an image into a negative? Something like below but I need to edit still.
My question is mainly the top bit of code if I can use that to invert the grayscale and black&white both to a negative?
import cv2
import numpy as np
img = cv2.imageread('imagename.jpg')
print(img.dtype)
image_neg = 255 - img
cv2.imshow('negative',image_neg)
cv2.waitKey(0)
#######################################
from images import Image
def invert(image):
def blackAndWhite(image):
blackPixel = (0, 0, 0)
whitePixel = (255, 255, 255)
for y in range(image.getHeight()):
for x in range(image.getWidth()):
(r, g, b) = image.getPixel(x, y)
average = (r + g + b) // 3
if average < 128:
image.setPixel(x, y, blackPixel)
else:
image.setPixel(x, y, whitePixel)
def grayscale(image):
for y in range(image.getHeight()):
for x in range(image.getWidth()):
(r, g, b) = image.getPixel(x, y)
r = int(r * 0.299)
g = int(g * 0.587)
b = int(b * 0.114)
lum = r + g + b
image.setPixel(x, y, (lum, lum, lum))
def main():
filename = input("Enter the image file name: ")
image = Image(filename)
#Invert image
invert(image)
image.draw()
#Covert to greyscale, then invert
"""grayscale(image)
invert(image)
image.draw()"""
#Convert to black and white, then invert
"""blackAndWhite(image)
invert(image)
image.draw()"""
if __name__ == "__main__":
main()
I receive the following error:
Traceback (most recent call last):
File "invert.py", line 14, in <module>
image_neg = 255 - image
NameError: name 'image' is not defined
I changed the code in the beginning to say this:
import cv2
import numpy as np
image = cv2.imageread('smokey.gif')
print(image.dtype)
image_neg = 255 - image
cv2.imshow('negative',image_neg)
cv2.waitKey(0)
Well I thought this would work but it tells me line - "invertedImage = cv2.bitwise_not(imageToInvert)" has a SyntaxError: invalid non-printable character U+00A0
I edited my code correctly on here (4 spaces) and I have no clue why it's not showing correctly still.
from images import Image
import cv2
def invert(image):
imageToInvert = cv2.imread(filepath)
invertedImage = cv2.bitwise_not(imageToInvert)
cv2.imgwrite("BWimage.png",invertedImage)
print("invertedĀ imageĀ saved")
File_path='smokey.gif'
invert(File_path)
Not sure what error you are getting. Maybe something here will help?
Syntax: cv2.cv.flip(src, flipCode[, dst] )
Parameters:
src: Input array.
dst: Output array of the same size and type as src.
flip code: A flag to specify how to flip the array; 0 means flipping around the x-axis and positive value (for example, 1) means flipping around y-axis. Negative value (for example, -1) means flipping around both axes.
Return Value: It returns an image.
As found in OpenCV
example code:
# Python program to explain cv2.flip() method
# importing cv2
import cv2
# path
path = r'C:\Users\user\Desktop\geeks14.png'
# Reading an image in default mode
src = cv2.imread(path)
# Window name in which image is displayed
window_name = 'Image'
# Using cv2.flip() method
# Use Flip code 0 to flip vertically
image = cv2.flip(src, 0)
# Displaying the image
cv2.imshow(window_name, image)
cv2.waitKey(0)
I'm attempting to write a floating point PIL image object out to a channel in an EXR file using OpenEXR.
I can read EXR data into a PIL image fine:
import OpenEXR
import Imath
from PIL import Image
import numpy as np
exrPath = "path/to/image.exr"
exrFile = OpenEXR.InputFile(exrPath)
pt = Imath.PixelType(Imath.PixelType.FLOAT)
dw = curFile.header()['dataWindow']
size = (dw.max.x - dw.min.x + 1, dw.max.y - dw.min.y + 1)
rgbf = [Image.frombytes("F", size, exrFile.channel(c, pt)) for c in ("R", "G", "B")]
I then run some operations over the PIL image data and want to save a single channel out as a new EXR. This is what I have so far:
exrHeader = OpenEXR.Header(pilImage.size[0],pilImage.size[1])
exrHeader["channels"] = {"GRAY":Imath.Channel(Imath.PixelType(Imath.PixelType.FLOAT), 1, 1)}
exrOut = OpenEXR.OutputFile("path/to/new.exr", exrHeader)
exrOut.writePixels({"GRAY": np.array(pilImage).astype(np.float32).tostring()})
But I get this error:
TypeError: Data for channel 'GRAY' should have size 67108864 but got 16777216
How do I convert a floating point PIL image to the correct format to write to a float EXR channel?
I got it working but don't understand it completely yet.
npImage = np.squeeze(pilImage)
size = img.shape
exrHeader = OpenEXR.Header(size[1], size[0])
exrHeader['channels'] = {"GRAY":Imath.Channel(Imath.PixelType(Imath.PixelType.FLOAT), 1, 1)}
exrOut = OpenEXR.OutputFile("path/to/new.exr", exrHeader)
GRAY = (npImage[:,:]).astype(np.float32).tobytes()
exrOut.writePixels({'GRAY' : R})
exrOut.close()
I've been playing around with PIL to get a hang of it and wanted to split up an image into its rgb channels, put it together again and show it.
import PIL.Image as Img
import numpy as np
img = Img.new('RGB', (10,10), color = 'cyan')
r,g,b = img.split()
pixels = np.array([np.asarray(r),np.asarray(g),np.asarray(b)])
new_img = Img.fromarray(pixels.astype(np.uint8))
new_img.show()
when I run the file it returns an Error:
File "C:\Program Files (x86)\Python38-32\lib\site-packages\PIL\Image.py", line 2716, in fromarray
raise TypeError("Cannot handle this data type: %s, %s" % typekey)
TypeError: Cannot handle this data type: (1, 1, 10), |u1
I've also tried it like this:
import PIL.Image as Img
import numpy as np
img = Img.new('RGB', (10,10), color = 'cyan')
r,g,b = img.split()
pixels = [np.asarray(r),np.asarray(g),np.asarray(b)]
new_img = Img.fromarray(pixels)
new_img.show()
Where I got this error:
File "C:\Program Files (x86)\Python38-32\lib\site-packages\PIL\Image.py", line 2704, in fromarray
arr = obj.__array_interface__
AttributeError: 'list' object has no attribute '__array_interface__'
So how do I have to put the r, g and b arrays back together correctly?
RGB image is made by stacking 3 colored channels one over the other on the z-axis. See this image for analogy,
pixels = np.array([np.asarray(r),np.asarray(g),np.asarray(b)])
This command places those 3 colored channels side by side, you can check shape using
print(pixels.shape)
(3, 10, 10)
This makes no sense to the interpreter thus the error message.
Each pixel in an RBG image is a tuple of red, green and blue color values.
thus shape take the form rows x cols x channels. You can achieve this by using np.stack
pixels = np.stack([np.asarray(r),np.asarray(g),np.asarray(b)], axis = 2)