Newbie here. =) I tried to reverse an image but there's an error and I don't know why :/
The Error:
Traceback (most recent call last):
File "C:/Users/Florian/Documents/ISN/S10/défi11.py", line 10, in <module>
im.putpixel((x,600-y),(p[0],p[1],p[2]))
File "C:\Python27\lib\site-packages\PIL\Image.py", line 1267, in putpixel
return self.im.putpixel(xy, value)
IndexError: image index out of range
The Code:
# -*- coding: cp1252 -*-
from PIL import Image
im=Image.open("H:\Belem.png")
L,H=im.size
for y in range(H):
for x in range(L):
p=im.getpixel((x,y))
im.putpixel((x,600-y),(p[0],p[1],p[2]))
im.save("H:\defi11.png")
I you mean to flip the image vertically, then you should do this:
for y in range(H/2):
for x in range(L):
p1=im.getpixel((x,y))
p2=im.getpixel((x,H-1-y))
im.putpixel((x,H-1-y),p1)
im.putpixel((x,y),p2)
This avoid overwriting pixels you will need later. It only loops over the first half of the lines, and exchanges them with the other half of the lines. Another approach would be to create a different output image with the same shape to write to:
im2 = im.copy()
for y in range(H):
for x in range(L):
p=im.getpixel((x,y))
im2.putpixel((x,H-1-y),p1)
im2.save("flipped.png")
This has the same effect as the version above, but uses more memory.
I guess the 600 in your example is a hardcoded version of H, but you have to subtract one extra from that (like I do above) in order to take into account that the indices go from 0 to H-1, not from 1 to H. On the first loop of your program y is zero, so 600-y is 600. If 600 is the height of the image, then you are going one beyond the last index (600-1), and hence triggering an IndexError exception.
If you have numpy installed, then a faster and simpler way to achieve the same thing is:
import numpy as np, PIL
original=PIL.Image.open("original.png")
arr = np.array(im)
flipped = PIL.Image.fromarray(arr[::-1])
flipped.save("flipped.png")
The numpy format also makes it easy to perform other operations like doing maths on the pixels.
Related
I'm using PIL to get the red values from every pixel of a picture. However, I need all the values to be in numpy arrays, because as far as I know, that is the only way to plot a 3D graph with a colourmap.
The problem is when I try to find the required red values using getpixel(), I get the following error:
Traceback (most recent call last):
File "C:\Users\Elitebook\Desktop\PIL\Smoke\get_data_smoke.py", line 14, in <module>
Z=im_rgb.getpixel((X,Y))[0]
File "C:\Users\Elitebook\AppData\Roaming\Python\Python37\site-packages\PIL\Image.py", line 1436, in getpixel
return self.im.getpixel(xy)
TypeError: an integer is required
So far, I have tried using x=x.astype(int) and dtype to get integer values, but none of them worked.
Here is my code:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
im=Image.open("smoke.jpg")
im_rgb=im.convert("RGB")
w,h=im.size
x=np.arange(1,w+1,1)
y=np.arange(1,h+1,1)
X,Y=np.meshgrid(x,y)
Z=im_rgb.getpixel((X,Y))[0]
fig=plt.figure()
ax=fig.add_subplot(projection='3d')
ax.plot(X,Y,Z)
plt.show()
If you want the image as a Numpy array, just use:
na = np.array(im_rgb)
By the way, the converse operation, turning a Numpy array back into a PIL Image is:
pilImage = Image.fromarray(na)
Your problem is that getpixel needs a sequence of integers. Your inputs X and Y were arrays. Therefore, you need some form of loop to extract the individual indexes:
x = np.arange(1,w+1,1)
y = np.arange(1,h+1,1)
X,Y = np.meshgrid(x,y)
Z = []
for i,j in zip(X,Y):
for ii, jj in zip(i,j):
Z.append(im_rgb.getpixel((int(ii),int(jj))))
I want to create a program that takes a picture of the same area at 2 different times and then compares the images, and then creates an entirely new image that has just the difference between the 2 images (what changed). I am using RGB values and I am looking to see if they are more than 90% different in value then I want to add those pixels to the new matrix, which will be mapped.
I am fairly new to Raspberry Pi and python so I ran into an error and I don't understand why it is giving me that error.
I have tried using both PIL and Numpy but both methods produce errors that I can't fix
THIS ISN'T THE ENTIRE CODE, BUT THIS IS THE FUNCTION THAT IS GIVING ME THE ERROR:
from PIL import Image
import numpy as np
import picamera
import time
import RPi.GPIO
from guizero import ...
def processimage():
before = Image.open('before.jpg')
after = Image.open('after.jpg')
beforeRGB = np.array(before)
afterRGB = np.array(after)
outputRGB = Image.new('RGB', (800,480))
x=0
y=0
for x in range(800):
for y in range(480):
if(((beforeRGB[x,y,0])/afterRGB[x,y,0])<0.9):
outputRGB[x,y,0] = afterRGB[x,y,0]
else:
output[x,y,0] = 255
if(((beforeRGB[x,y,1])/afterRGB[x,y,1])<0.9):
outputRGB[x,y,1] = afterRGB[x,y,1]
else:
output[x,y,1] = 255
if(((beforeRGB[x,y,2])/afterRGB[x,y,2])<0.9):
outputRGB[x,y,2] = afterRGB[x,y,2]
else:
output[x,y,2] = 255
y=y+1
x=x+1
Image.fromarray(outputRGB).save('output.jpg')
THIS IS THE ERROR I AM GETTING
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.5/tkinter/__init__.py", line 1562, in __call__
return self.func(*args)
File "/usr/local/lib/python3.5/dist-packages/guizero/PushButton.py",
line 146, in _command_callback
self._command()
File "/home/pi/ButtonTest/GUI_interface.py", line 70, in mode
lifetime(key)
File "/home/pi/ButtonTest/GUI_interface.py", line 158, in lifetime
processimage()
File "/home/pi/ButtonTest/GUI_interface.py", line 115, in processimage
outputRGB[x,y,0] = afterRGB(x,y,0)
TypeError: 'numpy.ndarray' object is not callable
1) The error message doesn't match the code. The error message is about a different version of the code where () where used accidentally instead of [], see last code line of the error message.
2) Iterating over individual pixels is very slow when using Python. Please read through a couple of image processing tutorials to get an understanding of vectorization and broadcasting.
For example, the code above could be shortened to something like:
output = np.where(beforeRGB/afterRGB < 0.9, afterRGB, 255]
3) for x in range() already iterates over all x values in the range. There is no need to increment x or y at the end of the loop.
4) The formula chosen for the image difference produces division by zero for pixels where at least one of the channels is 0. Do some research and choose a better metric for image differences.
This following is code using opencv in python to find the pixel difference of two images of the same size. However, it gives me an error in the last line and I don't know how to fix it.
if h1==h2:
if w1==w2:
c=np.zeros((h1,w1,3),np.uint8)
for i in range(img1.shape[0]):
for j in range(img1.shape[1]):
c[j][i]=img1[j][i]-img2[j][i]
IndexError: index 480 is out of bounds for axis 0 with size 480
You mixed up the indices; i belongs to img1.shape[0].
img1[j][i]-img2[j][i]
That said, numpy can vectorise this process for you and you can simply do
if img1.shape == img2.shape:
c = img1 - img2
However, you have to be careful with your data type. What if the pixel in one image is 0 and in the other is 32?
>>> np.uint8(0) - np.uint8(32)
Warning (from warnings module):
File "__main__", line 2
RuntimeWarning: overflow encountered in ubyte_scalars
224
You want to convert them to integers for the difference and if you want to keep the difference in the range 0-255, you can take the absolute of that.
c = img1.astype(int) - img2.astype(int)
# you can optionally do the following depending on what you want to do next
c = np.abs(c).astype(np.uint8)
OpenCV says a function that achieves all that for you, cv2.absdiff().
c = cv2.absdiff(img1, img2)
I have two pictures, one that was the original and another one that I have modified so that it's translated up and left a bit and then rotated 90 degrees (so the shape of the picture is transposed as well).
Now I'd like to determine how many pixels (or any distance unit) the modified picture is translated from the original, as well as the degrees of rotation relative to the original. Phase correlation is supposed to solve this problem by first converting the coordinates to logpolar coordinates, then doing a number of things so that in the end you get a correlation matrix. From that matrix I'm supposed to find the peak and the (x,y) combination will reveal the translation and rotation somehow. This link explains it much better:
Phase correlation
This is the following code I have:
import scipy as sp
from scipy import ndimage
from PIL import Image
from math import *
import numpy as np
def logpolar(input,silent=False):
# This takes a numpy array and returns it in Log-Polar coordinates.
if not silent: print("Creating log-polar coordinates...")
# Create a cartesian array which will be used to compute log-polar coordinates.
coordinates = sp.mgrid[0:max(input.shape)*2,0:360]
# Compute a normalized logarithmic gradient
log_r = 10**(coordinates[0,:]/(input.shape[0]*2.)*log10(input.shape[1]))
# Create a linear gradient going from 0 to 2*Pi
angle = 2.*pi*(coordinates[1,:]/360.)
# Using scipy's map_coordinates(), we map the input array on the log-polar
# coordinate. Do not forget to center the coordinates!
if not silent: print("Interpolation...")
lpinput = ndimage.interpolation.map_coordinates(input,
(log_r*sp.cos(angle)+input.shape[0]/2.,
log_r*sp.sin(angle)+input.shape[1]/2.),
order=3,mode='constant')
# Returning log-normal...
return lpinput
def load_image( infilename ) :
img = Image.open( infilename )
img.load()
data = np.asarray( img, dtype="int32" )
return data
def save_image( npdata, outfilename ) :
img = Image.fromarray( np.asarray( np.clip(npdata,0,255), dtype="uint8"), "L" )
img.save( outfilename )
image = load_image("C:/images/testing_image1.jpg")
target = load_image("C:/images/testing_otherimage.jpg")
# Conversion to log-polar coordinates
lpimage = logpolar(image)
lptarget = logpolar(target)
# Correlation through FFTs
Fcorr = np.fft.fft(lpimage)*np.fft.fft(lptarget)
correlation = np.fft.ifft(Fcorr)
The problem I have now is that this code will give as output:
Traceback (most recent call last):
File "./phase.py", line 44, in <module>
lpimage = logpolar(image)
File "./phase.py", line 24, in logpolar
order=3,mode='constant')
File "C:\Python27\lib\site-packages\scipy\ndimage\interpolation.py", line 295, in map_coordinates
raise RuntimeError('invalid shape for coordinate array')
RuntimeError: invalid shape for coordinate array
As I just have a very superficial understanding of what exactly is happening in the whole phase correlation process, I'm unclear on what the problem is about. I have tried to see if something's wrong with the input so I added save_image(image,"C:/testing.jpg") right after loading the image to see if there's something wrong with the numpy array from my images. And sure enough, the images I convert to np array, cannot be converted back to an image. This is the error I get:
Traceback (most recent call last):
File "./phase.py", line 41, in <module>
save_image(image,"C:/testing.jpg")
File "./phase.py", line 36, in save_image
img = Image.fromarray( np.asarray( np.clip(npdata,0,255), dtype="uint8"), "L" )
File "C:\Python27\lib\site-packages\PIL\Image.py", line 1917, in fromarray
raise ValueError("Too many dimensions.")
ValueError: Too many dimensions.
Taking a peek at the original documentation didn't give me much inspiration on what the problem could be. I don't think the code to convert images to numpy arrays are wrong as I've tested for the type with print type(image) and the results looked legit. Yet I can't convert it back to an image. Any help I can get would be greatly appreciated.
I think the problem is that you are trying to input a 3D image array (R,G,B,A?), into your function. Whereas the input only takes a 2D arrays. Try using a single channel to determine the transformation. E.g.
image = load_image("/path/to/image")[:,:,0]
I am trying to convert an image from cartesian to polar so that I can unravel the image, but I am getting a runtime error. If you are curious how this looks visually, see this example.
Code:
import scipy
import scipy.ndimage
import numpy as np
from math import *
import cv2
def logpolar(input):
# This takes a numpy array and returns it in Log-Polar coordinates.
coordinates = np.mgrid[0:max(input.shape[:])*2,0:360] # We create a cartesian array which will be used to compute log-polar coordinates.
log_r = 10**(coordinates[0,:]/(input.shape[0]*2.)*log10(input.shape[1])) # This contains a normalized logarithmic gradient
angle = 2.*pi*(coordinates[1,:]/360.) # This is a linear gradient going from 0 to 2*Pi
# Using scipy's map_coordinates(), we map the input array on the log-polar coordinate. Do not forget to center the coordinates!
lpinput = scipy.ndimage.interpolation.map_coordinates(input,(log_r*np.cos(angle)+input.shape[0]/2.,log_r*np.sin(angle)+input.shape[1]/2.),order=3,mode='constant')
# Returning log-normal...
return lpinput
# Load image
image = cv2.imread("test.jpg")
result = logpolar(image)
Error message in console:
Traceback (most recent call last):
File "test.py", line 23, in <module>
result = logpolar(image)
File "test.py", line 15, in logpolar
lpinput = scipy.ndimage.interpolation.map_coordinates(input,(log_r*np.cos(angle)+input.shape[0]/2.,log_r*np.sin(angle)+input.shape[1]/2.),order=3,mode='constant')
File "/Library/Python/2.7/site-packages/scipy-0.13.0.dev_c31f167_20130415-py2.7-macosx-10.8-intel.egg/scipy/ndimage/interpolation.py", line 295, in map_coordinates
raise RuntimeError('invalid shape for coordinate array')
RuntimeError: invalid shape for coordinate array
My first guess would be that you are passing in a colour image which is 3 dimensional. At first glance I don't think your code could handle that.
My guess was based off of the error you pasted, specifically
"invalid shape for coordinate array"
When using higher dimensional arrays like that usually you have to pass extra parameters around specifying which axis to repeat the operations over and even then sometimes it does not work. I didn't see a repeated extra integer at the end of your argument lists so I figured you weren't trying to handle that case explicitly and might have forgotten to check your array dimensions after reading in the image.
Glad it helped :)