At high school, we are beginning with Python and we are asked to program a small image processor using the Pillow
module. The goal is to open a file, then choose a filter.
The first filter I tried to program is to change the color temperature. But there's also a minimalist interface with tkinter that shows some buttons and it works without problems.
Here is the function that opens the file
def Ouvrir():
fichier = askopenfilename(title="Ouvrir une image",filetypes=[('jpg files','.jpg'),('all files','.*')])
global img
img =Image.open(fichier)
l, h = img.size
img.show() #visualisation de l'image
global img2
img2 = img #img2 est une copie de img
It creates a global img
image object that is loaded from the file. Then l
and h
are loaded with the width and height of the image.
Another global object image img2
is created for the output image, and it is a copy of img
.
Then here is the function that processes the image
def filtreTC(): #Filtre permettant de changer la température de couleur
coef = sliderTC.get() / 100 #On récupère le coefficient à partir de l'échelle. Le coefficient compris entre -1 et 1: -1 = froid (image bleu-vert), 0 = neutre, 1 = chaud (image orangée)
fenTC.destroy() #On ferme la fenêtre
if(coef <= 0): #Calcul des coefficients rouges, verte et bleus
coefR = 1 + coef
coefV = 1 + (coef / 2)
coefB = 1
else:
coefR = 1
coefV = 1 - (coef / 2)
coefB = 1 - coef
for y in range(0, h, 1):
for x in range(0, l, 1):
r, v, b = img.getpixel((x, y))
r = int(float(r * coefR))
v = int(float(v * coefV))
b = int(float(b * coefB))
img2.putpixel((x, y), (r, v, b))
img2.show()
It's a loop that scans through the whole image and takes a pixel from img
, multiply its rgb values by their corresponding coefficients, then puts that pixel in img2
The problem is that it doesn't work. It doesn't give any errors, but when it shows img2
it's the same as img1
, like the putpixel
function didn't do anything.
I checked a lot of things so I know the problem is neither the rgb values nor the x/y coordinates.
img2 = img
by img2 = Image.new("RGB", (l, h))
and what I get is a black image. img2.putpixel((x, y), (r, v, b))
by img2.putpixel((100, 100), (127, 127, 127))
so that way I should get a grey pixel near the top left corner. But I still got a black image. I then tried to remove
global img2
img2 = img
from the function that opens a file and put
img2 = Image.new("RGB", (l, h))
right after fenTC.destroy()
and I got this:
Exception in Tkinter callback
Traceback (most recent call last):
File "e:\xxxx\programmes\anaconda\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "H:\ISN\Programmes\TP-image\projet.py", line 62, in filtreTC
img2.show()
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 2016, in show
_show(self, title=title, command=command)
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 2876, in _show
_showxv(image, **options)
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 2881, in _showxv
ImageShow.show(image, title, **options)
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 51, in show
if viewer.show(image, title=title, **options):
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 75, in show
return self.show_image(image, **options)
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 95, in show_image
return self.show_file(self.save_image(image), **options)
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 91, in save_image
return image._dump(format=self.get_format(image), **self.options)
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 639, in _dump
self.save(filename, format, **options)
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 1969, in save
save_handler(self, fp, filename)
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\BmpImagePlugin.py", line 319, in _save
(rawmode, stride, -1))])
File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageFile.py", line 512, in _save
e.setimage(im.im, b)
SystemError: tile cannot extend outside image
Basically a lot of stuff I've got no idea what it means except:
SystemError: tile cannot extend outside image
I checked the x and y coordinates and they never went beyond the borders, so I don't understand what's this error.
I spent several hours to try figure out what the problem was and tried lots of different things but none of them worked. So I thought it was better to ask for help
Your problem is that you didn't create a copy . img2 = img
creates another reference to the same object, not a new, separate image.
To create a actual copy, use the image.copy()
method :
img2 = img.copy()
Next, I'd not use a loop and getpixel()
/ putpixel()
combinations. You are doing double work for RGB values that appear more than once. If you use the image.point()
method then you get to use your formula on each unique value in each band in the image, and leave the looping over all pixels to the library (much faster). It also makes the image copy for you!
You need to create a table; for values 0 through 255 for the R, G and B values, calculate the possible result, and put those 3 * 256 results in a long list:
coefG = [i * (1 - (coef / 2)) for i in range(256)]
if coef <= 0:
coefR = [i * (1 + coef) for i in range(256)]
coefB = list(range(256))
else:
coefR = list(range(256))
coefB = [i * (1 - coef) for i in range(256)]
img2 = img1.point(coefR + coefG + coefB)
The resulting table is used for each unique color value in the image.
You could also split the RGB image into separate bands, apply your different coefficient formulas to each separate band as a function then re-combine the bands into a new image:
r, g, b = img.split()
g = g.point(lambda i: i * (1 - (coef / 2)))
if coef <= 0:
r = r.point(lambda i: i * (1 + coef))
else:
b = b.point(lambda i: i * (1 - coef))
img = Image.merge('RGB', (r, g, b))
When creating an image filter, you'd really want to pass in the input image as a function argument rather than use globals. Pass in the coefficient as well:
def filtreTC(source_image, coef):
coefG = [i * (1 - (coef / 2)) for i in range(256)]
if coef <= 0:
coefR = [i * (1 + coef) for i in range(256)]
coefB = list(range(256))
else:
coefR = list(range(256))
coefB = [i * (1 - coef) for i in range(256)]
return source_image.point(coefR + coefG + coefB)
You can then store the result of the call in a global if you must, but the function can now stand on its own, and can be re-used anywhere that has a RGB PIL image object. You'd call the function with the slider value:
coef = sliderTC.get() / 100
fenTC.destroy()
img2 = filtreTC(img, coef)
Using the above on your profile image
with a coefficient of 0.75, gives us:
while -0.75 results in:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.