HowTo put region of Pyglet image into PIL Image? - image

My app reads frames from video (using pyglet), extracts a 'strip' (i.e. region - full width by 1 to 6 video lines), then pastes each strip (appends it) into an image that can later be written out an *.png file.
Problem is Pyglet GL images are stored in graphics memory, so are very limited re size.
My current klunky workaround is build up the to-be png image as small tiles (i.e. within the pyglet GL size limit), when the tile is full, write it out to a *png file, read that back in as a PIL Image file, then paste/append the tile image to the final PIL Image * png file.
I reckon it should be possible to convert the pyglet-GL strip to a PIL Image-friendly format, and paste/append that straight into the final PIL Image, thus having no need for the tile business, which greatly complicates things and has performance impact.
But I can't find how to get the strip data into a form that I can paste into a PIL Image.
Have seen many requests re converting the other way, but I've never run with the herd.

I know it's bad form to reply to one's own question, but I worked out an answer which may be useful to others, so here it is...
nextframe = source.get_next_video_frame() # get first video frame
while nextframe != None:# returns None at EOF
#
### extract strip data, conver to PIL Image-friendly form, paste itn into travo Image
#
strip = nextframe.get_region(0, (vid_frame_h//2)-(strip_h//2), strip_w, strip_h) # Extract strip from this frame
strip_image_data = strip.get_image_data()
strip_data = strip_image_data.get_data(strip_image_data.format, strip_image_data.pitch)
strip_Image = Image.frombuffer("RGB", (strip_w, strip_h), strip_data)
travo_image.paste(strip_Image, (0, travo_filled_to, strip_w, travo_filled_to + strip_h)) # paste strip image into travo_image
travo_filled_to = travo_filled_to + strip_h # update travo_filled pointer
nextframe = source.get_next_video_frame() # get next video frame (EOF returns None)
end of "while nextframe != None:"

Related

PIL output picture bigger than input

I am currently working on an automatic script for changing contrast on all the pictures inside a folder, using PIL (python). The problem is each output picture is bigger than input one... Here is my script:
from PIL import Image, ImageEnhance
import piexif
path="C:/User/pictures/"
all_files=["picture1.jpg", "picture2.jpg", "picture3.jpg"]
for i in range(len(all_files)):
im_path=all_files[i]
im = Image.open(path+im_path)
#load exif data
exif_dict = piexif.load(im.info['exif'])
exif_bytes = piexif.dump(exif_dict)
dpi = im.info["dpi"]
#image brightness enhancer
contraster = ImageEnhance.Contrast(im)
im_output = contraster.enhance(factor)
im_output.save(new_path+im_path, format="JPEG", quality=100, dpi=dpi, exif=exif_bytes, subsampling=0)
For example, my incoming jpg picture was 8.08Mo, and my new one is 15.8Mo, even if I chose a 0% change of contrast...
Thanks a for answering, have a nice week-end.
You have specified quality=100 against the recommendations of the library authors.
The image quality, on a scale from 0 (worst) to 95 (best). The default is 75. Values above 95 should be avoided; 100 disables portions of the JPEG compression algorithm, and results in large files with hardly any gain in image quality.

Frame Capture in external file Matlab

I captured a frame using capture() function in Matlab, However it returns a black image with a small area of captured whole image, I dont know why this is happening. I want to do this in every 5th iteration of loop.
I want to store that image in file, what syntax should I follow in order to check the image in file.
Further more, what are the suggestions for capturing frames in Matlab and save them in file for later estimation?
EDIT1: My code is working perfect now, but not capturing the frame, a black image instead.
My Code:
w = vrworld('myworld');
open(w);
c = vr.canvas(w, gcf, [30 30 300 200]);
z=capture(c);
image(z);
savename = [...
'C:\Users\My-PC\Documents\MATLAB\Project\image_', ...
num2str(1), '.jpg'];
imwrite(z, savename);

PyGame Poor Image Quality & Gradient Banding

I noticed that when displaying jpg or png images they look alot like a GIF file in that there is limited colors and "banding".
You can see the original and a screenshot attached. Kinda hard to tell scaled down but you can see it.
Actually better example. See the banding around the circle?
Here is my code:
#pygame code to render an image
import pygame, os
import time
image = 'gradient-test.png' #located in same folder as this file:resized in Photoshop
pygame.init() #I assume you did this?
SCREEN = pygame.display.set_mode((1366, 768))
pygame.mouse.set_pos((1366, 768))
picture = pygame.image.load(image)
SCREEN.blit(picture,(0,0))
pygame.display.update()
time.sleep(5)
It seems like a problem with the pixel format of your surface. You can add the following lines to your script to see if there's a difference between the pixel format of your image surface and your screen surface:
print 'picture', picture.get_bitsize()
print 'screen', SCREEN.get_bitsize()
It's good practice and recommended to always change the pixel format of any new surface to the pixel format of your screen surface by calling convert():
convert()
change the pixel format of an image
convert(Surface) -> Surface
Creates a new copy of the Surface with the pixel format changed ...
If no arguments are passed the new Surface will have the same pixel format as the display Surface. This is always the fastest format for blitting. It is a good idea to convert all Surfaces before they are blitted many times.
It's simple:
picture = pygame.image.load(image).convert() # added convert() call
Also, you can try to set the color depth of your screen manually, like:
SCREEN = pygame.display.set_mode((1366, 768),0, 32) # use 32-bit color depth

matplotlib.pyplot.imsave backend

I'm working in Spyder with matplotlib.pyplot and want to save numpy array to images.
The documentation of imsave() says, that the format to which I can save depends on the backend. So what exactly is the backend? I seem to be able to save .tiff images, but f.e. I want them to be saved as 8-bit tiffs instead of RGB-Tiffs. Any Idea where I can change that?
If you are trying to save an array as a tiff (with no axis markers ect) from mat, you might be better off using PIL.
(this assumes you are using ipython --pylab, so rand is defined)
write:
import PIL.Image as Image
im = Image.new('L',(100,100))
im.putdata(np.floor(rand(100,100) * 256).astype('uint8').ravel())
im.save('test.tif')
The ravel() is important, putdata expects a sequence (ie, 1D) not an array.
read :
im2 = Image.open('test.tif')
figure()
imshow(im2)
and the output file:
$ tiffinfo test.tif
TIFF Directory at offset 0x8 (8)
Image Width: 100 Image Length: 100
Bits/Sample: 8
Compression Scheme: None
Photometric Interpretation: min-is-black
Rows/Strip: 100
Planar Configuration: single image plane

How to read image from in memory buffer (StringIO) or from url with opencv python library

Just share a way to create opencv image object from in memory buffer or from url to improve performance.
Sometimes we get image binary from url, to avoid additional file IO, we want to imread this image from in memory buffer or from url, but imread only supports read image from file system with path.
To create an OpenCV image object with in memory buffer(StringIO), we can use OpenCV API imdecode, see code below:
import cv2
import numpy as np
from urllib2 import urlopen
from cStringIO import StringIO
def create_opencv_image_from_stringio(img_stream, cv2_img_flag=0):
img_stream.seek(0)
img_array = np.asarray(bytearray(img_stream.read()), dtype=np.uint8)
return cv2.imdecode(img_array, cv2_img_flag)
def create_opencv_image_from_url(url, cv2_img_flag=0):
request = urlopen(url)
img_array = np.asarray(bytearray(request.read()), dtype=np.uint8)
return cv2.imdecode(img_array, cv2_img_flag)
As pointed out in the comments to the accepted answer, it is outdated and no longer functional.
Luckily, I had to solve this very problem using Python 3.7 with OpenCV 4.0 recently.
To handle image loading from an URL or an in-memory buffer, I defined the following two functions:
import urllib.request
import cv2
import numpy as np
def get_opencv_img_from_buffer(buffer, flags):
bytes_as_np_array = np.frombuffer(buffer.read(), dtype=np.uint8)
return cv2.imdecode(bytes_as_np_array, flags)
def get_opencv_img_from_url(url, flags):
req = urllib.request.Request(url)
return get_opencv_img_from_buffer(urllib.request.urlopen(req), flags)
As you can see one depends on the other.
The first one, get_opencv_img_from_buffer, can be used to get an image object from an in-memory buffer. It assumes that the buffer has a read method and that it returns an instance of an object that implements the buffer protocol
The second one, get_opencv_img_from_url, generates an image directly from an URL.
The flags argument is passed on to cv2.imdecode,
which has the following constants predefined in cv2:
cv2.IMREAD_ANYCOLOR - If set, the image is read in any possible color format.
cv2.IMREAD_ANYDEPTH - If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
cv2.IMREAD_COLOR - If set, always convert image to the 3 channel BGR color image.
cv2.IMREAD_GRAYSCALE - If set, always convert image to the single channel grayscale image (codec internal conversion).
cv2.IMREAD_IGNORE_ORIENTATION - If set, do not rotate the image according to EXIF's orientation flag.
cv2.IMREAD_LOAD_GDAL - If set, use the gdal driver for loading the image.
cv2.IMREAD_REDUCED_COLOR_2 - If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2.
cv2.IMREAD_REDUCED_COLOR_4 - If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
cv2.IMREAD_REDUCED_COLOR_8 - If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
cv2.IMREAD_REDUCED_GRAYSCALE_2 - If set, always convert image to the single channel grayscale image and the image size reduced 1/2.
cv2.IMREAD_REDUCED_GRAYSCALE_4 - If set, always convert image to the single channel grayscale image and the image size reduced 1/4.
cv2.IMREAD_REDUCED_GRAYSCALE_8 - If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
cv2.IMREAD_UNCHANGED - If set, return the loaded image as is (with alpha channel, otherwise it gets cropped).

Resources