upsizing images with cubic interpolation in python PIL - python

Hi I am simply trying to resize a batch of images of size (a,b,3) to a bigger size (c, d, 3) (c>a, d>b) using cubic interpolation. But whenever I opened the resized images again after I seemingly resized successfully in the first place, I found the old dimension... It happened to every image and every dimension in my trials... Could anyone kindly point out what I was missing? Thanks a lot!
Here is my code:
from PIL import Image
im = Image.open("img0.jpg").convert("RGB")
im # the original size
<PIL.Image.Image image mode=RGB size=600x337 at 0x102D83450>
im.resize((800,400),Image.BICUBIC)
<PIL.Image.Image image mode=RGB size=800x400 at 0x102D834D0> # thought I was doing it right
im.save("resized.jpg")
im=Image.open("resized.jpg").convert("RGB")
im
<PIL.Image.Image image mode=RGB size=600x337 at 0x102D83490> # and the actual size seems even smaller than before!

The image resizing does not happen in-place. A new, resized image is returned, so you must save it.
new_img = im.resize((800,400),Image.BICUBIC)
new_img.save("resized.jpg")
or
im.resize((800,400),Image.BICUBIC).save("resized.jpg")
Whether or not a method or a function makes changes "in place" (which means there's no return value to grab and use, and a value of None is returned) or returns a value which you must use depends on the creator of the method or function. You can always, through trial and error, figure this out, but the better way is to look at the docs. For example, for the resize() method of PIL/Pillow, look at https://pillow.readthedocs.io/en/3.4.x/reference/Image.html#PIL.Image.Image.resize
There you will see that the function
Returns a resized copy of this image.
That tells you that you have to do something with the return value in order to preserve the effects of the method.
Additionally, if you go to http://effbot.org/imagingbook/image.htm and jump down to resize, you 'll see it says:
resize #
im.resize(size) ⇒ image
im.resize(size, filter) ⇒ image
The "arrow" pointing to the right is notation which says that the method returns a value. In this case, it returns an image.

Related

Using PIL to draw individual pixels, but the image is blurry

I am trying to create an image made up of coloured squares. I only need each square to be one pixel large, as it is just a single block colour. However, when I use this code, the image generated is extremely blurry. Is there anyway to make the boarders sharp?
def fancycolnw2(seq,m):
data=numbwall(seq,m)
#print(data)
for i in range(len(data)):
for j in range(len(data[i])):
if data[i][j]==' ':
data[i][j]=-1
im = Image.new('RGBA', (len(data[0]),len(data))) # create the Image of size 1 pixel
#print(data)
for i in range(len(data)-1):
for j in range(len(data[i])-1):
#print(i,j)
if data[i][j]==-1:
im.putpixel((j,i), ImageColor.getcolor('black', 'RGBA'))
if data[i][j]==0:
#print('howdy')
im.putpixel((j,i), ImageColor.getcolor('red', 'RGBA'))
if data[i][j]==1:
im.putpixel((j,i), ImageColor.getcolor('blue', 'RGBA'))
if data[i][j]==2:
im.putpixel((j,i), ImageColor.getcolor('grey', 'RGBA'))
im.show()
im.save('simplePixel.png') # or any image format
The result I get looks like this:
Image
It is the correct image, I just wish the boundaries between pixels were sharp. Any help would be greatly appreciated!
The image is perfectly sharp, but rather small. I suspect that you are "zooming in" to view it clearer, and that whatever program you are zooming with is filtering the image, because with most images this looks better. You need to find a viewing program that uses "nearest neighbour" resampling when zooming in, or generate a larger image to start with, for example by setting a 4-by-4 pixel block rather than individual pixels.
(Also, the code says "# or any other image format". Don’t use JPEG for this, as the lossy compression will likely wreck your image.)

Making a copy of an image

I am supposed to create several functions for my python program, and each program requires me to work with a copy of an input image. Hence, I need to write img = image.copy() for every function in my code. However, when I run the code, I am returned an AttributeError saying "'tuple' object has no attribute 'copy'. "
Given that I still have to include the statement img = image.copy() somewhere inside my function, how do I go about changing my code to remove this error? Do I need to change the image into numpy array first before I can use copy()?
Code:
def func(image):
img = image.copy() #error code appeared here
np_img = np.array(image)
rsize, csize = len(img), len(img[0]) #denoting the rows and columns of pixels of the image respectively
(the rest of the code)
Error message: AttributeError: 'tuple' object has no attribute 'copy'
Given that you have to put img=image.copy() in your functions, the easiest way should be to flip the order of np_img = np.array(image) and the former line. I'm assuming that your argument image has not been converted into a numpy array prior to what we see here.
After that, you should change img=image.copy() to the appropriate variables.
That said, I think it's best to load the image as a numpy matrix right away before doing anything else. That way, you can make a copy before any of your functions, lowering each function's costs too.

OpenCV Python converting color-space image to YCbCr

I need convert an image from BGR to YCbCr in Python using OpenCV.
I have an image with size/resolution 512x512, but when the image is opened, the size is 128x128.
I'm doing:
image = cv2.imread(imageName, cv2.COLOR_BGR2YCR_CB)
Could anyone help me?
The problem:
If you look at the docs for imread, the function takes an integer flag called imreadmodes. This flag seems to accept information about resizing the image, rather than changing color spaces.
The solution:
I believe you are looking for the cv2.cvtColor function which uses a flag to determine the source and destination colorspaces.
Both flags are simple integer enumerations. I assume the imread function is simply doing the best it can with the wrong type of flag.
You probably want to do something like:
BGRImage = cv2.imread(imageName)
YCrCbImage = cv2.cvtColor(BGRImage, cv2.COLOR_BGR2YCR_CB)

Working with truncated images with PIL

I am trying to get the Python 2.7 PIL Library to work with JPEG images that are only available as a stream coming from a HDD image and are not complete.
I have set the option:
ImageFile.LOAD_TRUNCATED_IMAGES = True
And load the stream as far as it is available (or better said: as far as I am 100% sure that this data is still a image, not some other file type). I have tested different things and as far as I can tell (for JPEGs) PIL only accepts it as a valid JPEG Image if it finds the 0xFFDA (Start of Scan Marker). This is a short example of how I load the data:
from PIL import Image
from StringIO import StringIO
ImageFile.LOAD_TRUNCATED_IMAGES = True
with open("/path/to/image.raw", 'rb') as fp:
fp.seek("""jump to position in image where JPEG starts""")
data = fp.read("""number of bytes I know that those belong to that jpeg""")
img = Image.open(StringIO(data)) # This would throw exception if the data does
# not contain the 0xffda marker
pixel = img.load() # Would throw exception if LOAD_TRUNCATED_IMAGES = false
height,width = img.size
for i in range(height):
for j in range(width):
print pixel[i,j]
On the very last line I expected (or hoped) to see at least the read pixel data to be displayed. But for every pixel it returns (0,0,0).
The Question: Is what I am trying here not possible with PIL?
Some weeks ago I tried the same with a image file I truncated myself, simply by cutting data from it with an editor. It worked for the pixel-data that was available. As soon as it reached a pixel that I cut off, the program threw an exception (I will try this again later today to make sure that I am not remembering wrong).
If somebody is wondering why I am doing this: I need to make sure that the image/picture inside that hdd image is in consecutive blocks/clusters and is not fragmented. To make sure of this I wanted to use pixel matching.
EDIT:
I have tried it again and this is what I have seen.
I opened a truncated image in GIMP and it showed me a few pixel lines in the upper part, but PIL was not able to at least give me the RGB values of those pixels. It always returns (0,0,0).
I made the image slightly bigger such that the lower 4/5 of the image was not visible, but that was enough for PIL to show me the RGB values that were available. Everything else was (0,0,0).
I am still not 100% sure whether PIL can show me the RGB values, even if only view pixel-data is available.
I would try it with an uncompressed format like TGA. JPG being a compressed format may not make any sense to extract pixels from an incomplete image. JPEG actually stores the parameters for equations that describe the image, not pixel values. When you query a JPEG for a pixel value it evaluates the equations at that point and returns the result.
I have the same problem with Pillow==9.2.0
Let's downgrade to Pillow==8.3.2 and it works.
I don't really know about streaming, but I think that you simply cannot access rgb value the way you do.
Try:
rgb_im = img.convert('RGB')
r, g, b = rgb_im.getpixel((i, j))

opencv zoom function strange results

i am trying to write a zoom function which looks something like this:
centre = ((im.width-1)/2, (im.height-1)/2)
width = int(im.width/(2.0*level))
height = int(im.height/(2.0*level))
rect = (centre[0]-width, centre[1]-height, width*2, height*2)
dst = cv.GetSubRect(im, rect)
cv.Resize(dst, im)
when I use exactly what is written above, I get an odd result where the bottom half of the resultant image is distorted and blurry. However when I replace the line cv.Resize(dst, im) with
size = cv.CloneImage(im)
cv.Resize(dst, size)
im = size
it works fine. Why is this? is there something fundamentally wrong with the way i am performing the zoom?
cv.Resize requires source and destination to be separate memory locations.
Now in the first snippet of your code, you are using cv.GetSubRect to generate an object pointing to area of image which you wish to zoom in. Here the new object is NOT pointing to a new memory location. It is pointing to a memory location which is a subset of original object.
Since cv.Resize requires both the memory locations to be different, what you are getting is a result of undefined behavior.
In the second part of your code you are fulfilling this criteria by using cv.CloneImage.
you are first creating a copy of im (i.e. size. however you could have used a blank image aswell) and then you are using cv.Resize to resize dst and write the resulting image in size.
My advice is to go through the function documentation before using them.

Categories