I have opened a grayscale image using the Python Imaging Library, copied every pixel value into another image variable of same size and saved it. Now when I open the new image with an image viewer it looks reddish. I have used the Image.new() method with and without the "white" and "black" arguments got the same reddish output.
My code:
from PIL import Image
import math
def run():
im = Image.open("hrabowski.jpg")
pix = im.load()
print im.size
# print pix[0, 1]
im2 = Image.new("RGB", (2400, 2400))
for i in range(im.size[0]):
for j in range(im.size[0]):
im2.putpixel((i, j), pix[i, j])
im2.save("hrabowski-2400-2400.jpg")
Original image (scaled down to 500 x 500):
Python output of my code (scaled down to 500 x 500):
Could anyone please tell me what I am doing wrong?
Your problem is that you want to create an RGB image which has three channels. Therefore one pixel value consists of three values and not only one (in your case use the gray value of the original image for each of the channels).
I have modified the code accordingly.
A side remark: I am almost sure that there is a better way to do what you want to achieve, there is usually no need to loop through single pixels, but I am not sure what you are after.
from PIL import Image
import math
def run():
im = Image.open("ZHiG0.jpg")
pix = im.load()
print im.size
# print pix[0, 1]
im2 = Image.new("RGB", (2400, 2400))
for i in range(im.size[0]):
for j in range(im.size[0]):
im2.putpixel((i, j), (pix[i, j],pix[i, j],pix[i, j]))
im2.save("ZHiG0-2400-2400.jpg")
run()
Related
I have a 2d list in python, and I want to make a graphical pic of the data. Maybe a n by m column grid where each square is a different color of grey depending on the value in my 2d list.
However, I can't seem to figure out how to create images using PIL. This is some of the stuff I've been messing with:
def createImage():
img = Image.new('L', (100,100), 'white')
img.save('test.bmp')
for i in range(0,15):
for j in range(0,15):
img.putpixel((i,j), (255,255,255))
However, I'm getting an error saying that an integer is required (problem on the line with the putpixel)
This is from http://en.wikibooks.org/wiki/Python_Imaging_Library/Editing_Pixels:
from PIL import Image
img = Image.new( 'RGB', (255,255), "black") # Create a new black image
pixels = img.load() # Create the pixel map
for i in range(img.size[0]): # For every pixel:
for j in range(img.size[1]):
pixels[i,j] = (i, j, 100) # Set the colour accordingly
img.show()
My goal is to generate a color per pixel in order to fill up the whole canvas however the image generated always turns out black with only one of its pixels changed color, I can't seem to figure what I'm doing wrong.
import random
from PIL import Image
canvas = Image.new("RGB", (300,300))
y = random.randint(1, canvas.width)
x = random.randint(1, canvas.width)
r = random.randint(0,255)
g = random.randint(0,255)
b = random.randint(0,255)
rgb = (r,g,b)
for i in range(canvas.width):
canvas.putpixel((x,y), (rgb))
canvas.save("test.png", "PNG")
print("Image saved successfully.")
You really should try and avoid using for loops in any Python image processing - they are slow and error-prone.
The easiest and fastest way to make a random image is using vectorised Numpy functions like this:
import numpy as np
from PIL import Image
# Create Numpy array 300x300x3 of random uint8
data = np.random.randint(0, 256, (300,300,3), dtype=np.uint8)
# Make into PIL Image
im = Image.fromarray(data)
The problem with your code is that you are not iterating over every pixel. I've modified your code to iterate over every pixel, check whether or not it is black (0,0,0), then place a pixel on that iteration with your randomly-generated rgb value. Then, I regenerate 3 new random numbers and place them back into the rgb tuple causing the next pixel in the loop to have a different rgb value.
The x and y definitions are redundant, as you want a random color for every pixel but do not want random pixels, so I have removed them. I added a declaration, pixels = canvas.load() which allocates memory for the pixels so you can iterate over them and change each individual color. I heavily relied on this similar stackoverflow question, if you want further information. Here is my code:
canvas = Image.new("RGB", (300,300))
pixels = canvas.load()
width, height = canvas.size
for i in range(width):
for j in range(height):
if pixels[i,j] == (0,0,0):
r = random.randint(0,255)
g = random.randint(0,255)
b = random.randint(0,255)
rgb = (r,g,b)
canvas.putpixel((i,j), (rgb))
canvas.save("test.png", "PNG")
print("Image saved successfully.")
Here is the output produced:
So in my coursework, I am supposed to change the different variations of colors and get an image that looks like the example provided. I have gotten halfway there, but for the life of me cannot figure out how to get the colors to change, even a little bit. Even if the code runs without errors, the colors will not change
i've tried numpy arrays, editing the pixel color, etc. I can not get anything to work.
import PIL
from PIL import Image
from PIL import ImageEnhance
from PIL import ImageDraw
from PIL import ImageFont
fnt = ImageFont.truetype('readonly/fanwood-webfont.ttf', 75)
# read image and convert to RGB
image=Image.open("readonly/msi_recruitment.gif")
image=image.convert('RGB')
drawing_object = ImageDraw.Draw(image)
# build a list of 9 images which have different brightnesses
enhancer=ImageEnhance.Brightness(image)
images=[]
x = 1
for i in range(0, 10):
pixels = img.load()
print(image.size)
x += 1
z = x
if x%3 == 1 :
z = 9
drawing_object.rectangle((0,450,800,325), fill='black')
drawing_object.text((20,350),'channel intensity o 0.{}'.format(z), font=fnt, fill=(255,255,255))
elif x%3 == 0:
z = 5
drawing_object.rectangle((0,450,800,325), fill='black')
drawing_object.text((20,350),'channel intensity o 0.{}'.format(z), font=fnt, fill=(255,255,255))
else:
z = 1
drawing_object.rectangle((0,450,800,325), fill='black')
drawing_object.text((20,350),'channel intensity o 0.{}'.format(z), font=fnt, fill=(255,255,255))
images.append(enhancer.enhance(10/10))
## create a contact sheet from different brightnesses
first_image=images[0]
contact_sheet=PIL.Image.new(first_image.mode, (first_image.width*3,first_image.height*3))
x=0
y=0
for img in images:
# Lets paste the current image into the contact sheet
contact_sheet.paste(img, (x, y) )
# Now we update our X position. If it is going to be the width of the image, then we set it to 0
# and update Y as well to point to the next "line" of the contact sheet.
if x+first_image.width == contact_sheet.width:
x=0
y=y+first_image.height
else:
x=x+first_image.width
# resize and display the contact sheet
contact_sheet = contact_sheet.resize((int(contact_sheet.width/2),int(contact_sheet.height/2) ))
display(contact_sheet)
So in general you can use OpenCVs ColorMap to change colors in your image:
import cv2
img = cv2.imread(r"<IMAGE PATH>")
img = cv2.applyColorMap(img, cv2.COLORMAP_JET) # Change colors of image with predefined colormap
# Display the new image
cv2.imshow("img", img)
cv2.waitKey()
Now if you want to create your own colormap instead of using a predefined one in OpenCV you can do it with cv2.LUT() (OpenCV Documentation)
Example Input:
Example Output:
And here would be a quick example of how to change Gamma with this approach:
def adjust_gamma(img, gamma=1.0):
assert (img.shape[0] == 1)
invGamma = 1.0 / gamma
table = np.array([((i / 255.0) ** invGamma) *
255 for i in np.arange(0, 256)]).astype("uint8")
new_img = cv2.LUT(np.array(img, dtype=np.uint8), table)
return new_img
It looks like you have a typo in your loop:
for i in range(0, 10):
# if-elses
...
images.append(enhancer.enhance(10/10))
You're enhancing the image with a factor of 1.0 at each iteration, which according to the docs:
Adjust image brightness.
This class can be used to control the brightness of an image. An enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the original image.
Using z, which I suspect was your intention, will give you the tiers of brightness your comments describe:
for i in range(0, 10):
# if-elses
...
images.append(enhancer.enhance(z/10))
Edit: changed assumed value from i to z, based on the text you're writing.
I should also point out that you probably want to create a temp "watermark" image during the for-loop to apply the text/rectangle to. Since the ImageDraw objects modify the image in-place, you're applying the text on top of each other at each iteration, causing some weird text on the later images.
I was trying to change pixel of an image in python using this question. If mode is 0, it changes first pixel in top right corner of image to grey(#C8C8C8). But it doesn't change. There is not enough documentation about draw.point(). What is the problem with this code?
import random
from PIL import Image, ImageDraw
mode = 0
image = Image.open("dom.jpg")
draw = ImageDraw.Draw(image)
width = image.size[0]
height = image.size[1]
pix = image.load()
string = "kod"
n = 0
if (mode == 0):
draw.point((0, 0), (200, 200, 200))
if(mode == 1):
print(pix[0,0][0])
image.save("dom.jpg", "JPEG")
del draw
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.
I was trying to use the PIL module to make the colorpicker gradient
Like this.
I made a code to test out:
from PIL import Image
img = Image.new('HSV', (255,255), "white")
pix = img.load()
H = 0
for x in range(img.size[0]):
S =(int(100*(x/float(img.size[0])))) # A % of image width
for y in range(img.size[1]):
V = (int(100*(1-(y/float(img.size[1]))))) # A % of image height
pix[x,y] = (H,S,V)
img.show()
But my image turns out dark. What did I do wrong?
You are generating S and V values in the 0..100 range. However, I'm pretty sure that a PIL HSV image uses 0..255 values; in other words, you're only using the bottom 40% of the range.