Pillow library quantize not working on my raspberry pi4b - python-imaging-library

Code basically grayscale, pixelize and resize to a 32x32 format, everything works except when i put in the code in line 11 which limits the picture to 8 shades of grey. This causes the code to come up with the error "ValueError: Conversion not supported"
# Tested on Raspberry Pi 4 Model B
# Huats Club 2022 for the Pixel-Tint Project
from PIL import Image, ImageOps
#from student_pub import *
## open image file
myImage = Image.open('Pixelizer/pokeball.png')
myImage.show()
## greyscale image file
greyImage = ImageOps.grayscale(myImage)
#greyImage.show()
## Limiting to 8 shades of greyscale colour
greyQuantize = greyImage.quantize(8)
#greyQuantize.show()
## resize to 32 x 32 pixels
smallImage = greyQuantize.resize((32,32), Image.BILINEAR)
#smallImage.show()
## Blow it back up to original photo size (32 x 32 pixels upscale)
resultImage = smallImage.resize(myImage.size, Image.NEAREST)
resultImage.show()
## Write Image to save .png file
#resultImage.save('cartoon.png')
# Retrieving pixel value and formating it into list of list
x = 32; k = 0; outputValue = [0 for i in range(x)]
for i in range(x):
outputValue[i] = [0 for j in range(x)]
pixValue = list(smallImage.getdata())
for i in range(x):
for j in range(x):
outputValue[i][j] = pixValue[k]
k = k + 1;
print(outputValue)
#pubpic(outputValue)
the code works fine without the greyQuantize = greyImage.quantize(8) and im new so i dont really know how to fix this problem. The code is running on my pi raspberry 4b with python 3.7.3 using the thonny python ide editor. u can put in your own pictures on line 7 just list the directory and image file such as 'folder/file.png'

Related

Binarizing 3-channel images

circle_folder = 'C:\Users\MyPC\Documents\CR\start\circle';
name_circle = dir(fullfile(circle_folder, '*.png'));
total_circle = numel(name_circle);
rez_circle = [25 25];
m_circle = zeros(25*25, 5);
for n_circle = 1:total_circle
full_circle = fullfile(circle_folder, name_circle(n_circle).name);
images_circle = imread(full_circle);
images_circle = imresize(images_circle, rez_circle);
store_circle = imbinarize(images_circle);
store_circle = store_circle(:);
m_circle(:, n_circle) = store_circle;
figure(n_circle);
imshow(m_circle);
end
I'm trying to pull images from the folder in question, resize them to 25 by 25 pixels, then turn them into a binary matrix. The code works until the point i attempt to fit the images into said matrix. If I make the matrix bigger, so it becomes 1875-by-1, it works, however, I do need the matrix to be of this size.
What happened is that you loaded an m-by-n-by-3 image, i.e. a 3 channel image. You used imresize() to resize each channel independently, ending up with a 25-by-25-by-3 image. imbinarize() finally works on each channel separately as well.
Instead, before resizing, call rgb2gray(images_circle) to change your 3 channel image to a 1 channel image. Then you can call imresize() and imbinarize(), resulting in your desired 25-by-25 binary image.

Discord.py Image Editing with Python Imaging Library only works for some pictures?

I've tried an image-editing-effect which should recolor a picture with little black dots, however it only works for certain images and I honestly don't know why. Any ideas?
#url = member.avatar_url
#print(url)
#response = requests.get(url=url, stream=True).raw
#imag = Image.open(response)
imag = Image.open("unknown.png")
#out = Image.new('I', imag.size)
i = 0
width, height = imag.size
for x in range(width):
i+=1
for y in range(height):
if i ==5:
# changes every 5th pixel to a certain brightness value
r,g,b,a = imag.getpixel((x,y))
print(imag.getpixel((x,y)))
brightness = int(sum([r,g,b])/3)
print(brightness)
imag.putpixel((x, y), (brightness,brightness,brightness,255))
i= 0
else:
i += 1
imag.putpixel((x,y),(255,255,255,255))
imag.save("test.png")
The comments are what I would've used if my tests had worked. Using local pngs also don't work all the time.
Your image that doesn't work doesn't have an alpha channel but your code assumes it does. Try forcing in an alpha channel on opening like this:
imag = Image.open("unknown.png").convert('RGBA')
See also What's the difference between a "P" and "L" mode image in PIL?
A couple of other ideas too:
looping over images with Python for loops is slow and inefficient - in general, try to find a vectorised Numpy alternative
you have an alpha channel but set it to 255 (i.e. opaque) everywhere, so in reality, you may as well not have it and save roughly 1/4 of the file size
your output image is RGB with all 3 components set identically - that is really a greyscale image, so you could create it as such and your output file will be 1/3 the size
So, here is an alternative rendition:
#!/usr/bin/env python3
from PIL import Image
import numpy as np
# Load image and ensure neither palette nor alpha
im = Image.open('paddington.png').convert('RGB')
# Make into Numpy array
na = np.array(im)
# Calculate greyscale image as mean of R, G and B channels
grey = np.mean(na, axis=-1).astype(np.uint8)
# Make white output image
out = np.full(grey.shape, 255, dtype=np.uint8)
# Copy across selected pixels
out[1::6, 1::4] = grey[1::6, 1::4]
out[3::6, 0::4] = grey[3::6, 0::4]
out[5::6, 2::4] = grey[5::6, 2::4]
# Revert to PIL Image
Image.fromarray(out).save('result.png')
That transforms this:
into this:
If you accept calculating the greyscale with the normal method, rather than averaging R, G and B, you could change to this:
im = Image.open('paddington.png').convert('L')
and remove the line that does the averaging:
grey = np.mean(na, axis=-1).astype(np.uint8)

How to separate human body from background in an image

I have been trying to separate the human body in an image from the background, but all the methods I have seen don't seem to work very well for me.
I have collected the following images;
The image of the background
The image of the background with the person in it.
Now I want to cut out the person from the background.
I tried subtracting the image of the background from the image with the person using res = cv2.subtract(background, foreground) (I am new to image processing).
Background subtraction methods in opencv like cv2.BackgroundSubtractorMOG2() and cv2.BackgroundSubtractorMOG2() only works with videos or image sequence and contour detection methods I have seen are only for solid shapes.
And grabCut doesn't quite work well for me because I would like to automate the process.
Given the images I have (Image of the background and image of the background with the person in it), is there a method of cutting the person out from the background?
I wouldn't recommend a neural net for this problem. That's a lot of work for something like this where you have a known background. I'll walk through the steps I took to do the background segmentation on this image.
First I shifted into the LAB color space to get some light-resistant channels to work with. I did a simple subtractions of foreground and background and combined the a and b channels.
You can see that there is still significant color change in the background even with a less light-sensitive color channel. This is likely due to the auto white balance on the camera, you can see that some of the background colors change when you step into view.
The next step I took was thresholding off of this image. The optimal threshold values may not always be the same, you'll have to adjust to a range that works well for your set of photos.
I used openCV's findContours function to get the segmentation points of each blob and I filtered the available contours by size. I set a size threshold of 15000. For reference, the person in the image had a pixel area of 27551.
Then it's just a matter of cropping out the contour.
This technique works for any good thresholding strategy. If you can improve the consistency of your pictures by turning off auto settings and ensure good contrast of the person against the wall then you can use simpler thresholding strategies and get good results.
Just for fun:
Edit:
I forgot to add in the code I used:
import cv2
import numpy as np
# rescale values
def rescale(img, orig, new):
img = np.divide(img, orig);
img = np.multiply(img, new);
img = img.astype(np.uint8);
return img;
# get abs(diff) of all hue values
def diff(bg, fg):
# do both sides
lh = bg - fg;
rh = fg - bg;
# pick minimum # this works because of uint wrapping
low = np.minimum(lh, rh);
return low;
# load image
bg = cv2.imread("back.jpg");
fg = cv2.imread("person.jpg");
fg_original = fg.copy();
# blur
bg = cv2.blur(bg,(5,5));
fg = cv2.blur(fg,(5,5));
# convert to lab
bg_lab = cv2.cvtColor(bg, cv2.COLOR_BGR2LAB);
fg_lab = cv2.cvtColor(fg, cv2.COLOR_BGR2LAB);
bl, ba, bb = cv2.split(bg_lab);
fl, fa, fb = cv2.split(fg_lab);
# subtract
d_b = diff(bb, fb);
d_a = diff(ba, fa);
# rescale for contrast
d_b = rescale(d_b, np.max(d_b), 255);
d_a = rescale(d_a, np.max(d_a), 255);
# combine
combined = np.maximum(d_b, d_a);
# threshold
# check your threshold range, this will work for
# this image, but may not work for others
# in general: having a strong contrast with the wall makes this easier
thresh = cv2.inRange(combined, 70, 255);
# opening and closing
kernel = np.ones((3,3), np.uint8);
# closing
thresh = cv2.dilate(thresh, kernel, iterations = 2);
thresh = cv2.erode(thresh, kernel, iterations = 2);
# opening
thresh = cv2.erode(thresh, kernel, iterations = 2);
thresh = cv2.dilate(thresh, kernel, iterations = 3);
# contours
_, contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);
# filter contours by size
big_cntrs = [];
marked = fg_original.copy();
for contour in contours:
area = cv2.contourArea(contour);
if area > 15000:
print(area);
big_cntrs.append(contour);
cv2.drawContours(marked, big_cntrs, -1, (0, 255, 0), 3);
# create a mask of the contoured image
mask = np.zeros_like(fb);
mask = cv2.drawContours(mask, big_cntrs, -1, 255, -1);
# erode mask slightly (boundary pixels on wall get color shifted)
mask = cv2.erode(mask, kernel, iterations = 1);
# crop out
out = np.zeros_like(fg_original) # Extract out the object and place into output image
out[mask == 255] = fg_original[mask == 255];
# show
cv2.imshow("combined", combined);
cv2.imshow("thresh", thresh);
cv2.imshow("marked", marked);
# cv2.imshow("masked", mask);
cv2.imshow("out", out);
cv2.waitKey(0);
Since it is very easy to find dataset consist a lot of human body, I suggest you to implement neural network segmentation tecniques to extract human body perfectly. Please check this link to see similar example.

Is there any way to read Digital Number in the oven using pytesseract OCR?

I'm doing small project using tesseract OCR.
What I want to read is Digital Number which is generated by oven.
I pre-treat the image using openCV
but, tesseract can't read the image correct.
eg. 194 as 794..
let me know is there any way to deal with this.
thanks.
the Image which I want to read is shown below
import cv2
import numpy
img_color = cv2.imread('20190509_103247.jpg', cv2.IMREAD_COLOR)
dst = img_color.copy()
roi = img_color[1600:1800,600:1100]
dst[0:200,0:500]=roi
blur = cv2.GaussianBlur(roi,(5,5),0)
gray_dst = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
ret, thr = cv2.threshold(gray_dst, 70, 255,cv2.THRESH_BINARY)
canny = cv2.Canny(roi,100,255)
sobel = cv2.Sobel(gray_dst,cv2.CV_8U,1,0,3)
laplacian = cv2.Laplacian(gray_dst,cv2.CV_8U,ksize=3)
rev = cv2.bitwise_not(canny)
# blur = cv2.GaussianBlur(roi,(5,5),0)
# stencil = numpy.zeros(rev.shape).astype(rev.dtype)
# _, contours, _ = cv2.findContours(rev, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# color = [255, 255, 255]
# cv2.fillPoly(stencil, contours, color)
# result = cv2.bitwise_and(rev, stencil)
cv2.namedWindow('Show Image')
cv2.imshow('Show Image', rev)
cv2.waitKey(0)
cv2.imwrite('savedimage.jpg', rev)
cv2.destroyAllWindows()
You can create training data that will work for your font / glyphs to improve how the numeric display gets transformed to the correct digits.
References:
https://github.com/tesseract-ocr/tesseract/wiki/TrainingTesseract-4.00#creating-training-data
https://github.com/DevashishPrasad/LCD-OCR

Matlab code to generate images from entropy

Could you please help me with this question:
Assume that on average in binary images, 75% of the pixels are white, and 25% are black. What is the entropy of this source? Model this source in Matlab and generate some sample images according to this process
To find the entropy, you just need to apply the definition:
H = -0.25 * log2(0.25) - 0.75 * log2(0.75)
Since we are using log2, the result will be in bits.
As for generating a Matlab B&W (i.e. binary) image of size 512x512, you can simply do:
im = rand(512) < 0.75;
By convention, true = 1 = white and false = 0 = black.