Keep track of reference pixel in PIL imgage while doing transformations - python

I want to keep track of a point/pixel for reference in a PIL image while I do a (perspective) transformation and cut off the transparent borders.
from PIL import Image
# load image
img = Image.open("img.png")
# do some perspective transformation
img.transform(new_size, Image.PERSPECTIVE, mapping_coeffs)
# cut the borders
img = img.crop(img.getbbox())
For the cropping I could keep track of a position by subtracting the size of the padding. But how can I do this for a perspective transformation, or even multiple transformations in a row?

For others with the same question, I made a black image with only the reference pixel in white using NumPy and transformed it in the same way as my image.
from PIL import Image
import numpy as np
# get black img with the same size
refArray = np.zeros(PILimg.size)
# make the reference pixel white
refArray[xRef, yRef] = 1e8
# to PIL image object
refImg = Image.fromarray(refArray.T)
Do the same transformations with the reference image, and then find the max value in the transformed reference image
ref = np.array(refImg).T
xRef, yRef = np.unravel_index(np.argmax(ref), ref.shape)
edit: For some transformations the pixel disappears, this is solved by using a small square of pixels (5x5) instead of a single pixel.

Related

python how to resize(shrink) image without losing quality

I want to resize png picture 476x402 to 439x371, and I used resize method of PIL(image) or opencv, however, it will loss some sharp. After resize, The picture becomes blurred.
How to resize(shrink) image without losing sharpness with use python?
from skimage import transform, data, io
from PIL import Image
import os
import cv2
infile = 'D:/files/script/org/test.png'
outfile = 'D:/files/script/out/test.png'
''' PIL'''
def fixed_size1(width, height):
im = Image.open(infile)
out = im.resize((width, height),Image.ANTIALIAS)
out.save(outfile)
''' open cv'''
def fixed_size2(width, height):
img_array = cv2.imread(infile)
new_array = cv2.resize(img_array, (width, height), interpolation=cv2.INTER_CUBIC)
cv2.imwrite(outfile, new_array)
def fixed_size3(width, height):
img = io.imread(infile)
dst = transform.resize(img, (439, 371))
io.imsave(outfile, dst)
fixed_size2(371, 439)
src:476x402
resized:439x371
How can you pack 2000 pixels into a box that only holds 1800? You can't.
Putting the same amount of information (stored as pixels in your source image) into a smaller pixelarea only works by
throwing away pixels (i.e. discarding single values or by cropping an image which is not what you want to do)
blending neighbouring pixels into some kind of weighted average and replace say 476 pixels with slightly altered 439 pixels
That is exactly what happens when resizing images. Some kind of algorithm (interpolation=cv2.INTER_CUBIC, others here) tweaks the pixel values to merge/average them so you do not loose too much of information.
You can try to change the algorithm or you can apply further postprocessing ("sharpening") to enrich the contrasts again.
Upon storing the image, certain formats do "lossy" storage to minimize file size (JPG) others are lossless (PNG, TIFF, JPG2000, ...) which further might blur your image if you choose a lossy image format.
See
Shrink/resize an image without interpolation
How can I sharpen an image in OpenCV?

In pytyon is it possible to prevent the text's pixel while removing lines in image?

I'm working in text extraction process inside the table.But while removing the table lines it affecting the text's pixel.is is possible to keep the text pixel which is overlays on the table line pixel.
original image as RGB
this image is the cropped from original image for reference
output region
Use eroded (or dilated black objects) second image as mask for first image.
import cv2
import numpy as np
#images need equal size
original=cv2.imread('RdfpD.png')
mask = cv2.imread('zxLX4.png', cv2.IMREAD_GRAYSCALE)
se=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,5))
ret,thresh = cv2.threshold(mask,60,255,cv2.THRESH_BINARY_INV)
dilate = cv2.dilate(thresh,se,iterations = 1)
dilate=cv2.bitwise_not(dilate)
dilate=cv2.cvtColor(dilate, cv2.COLOR_GRAY2BGR)
out=cv2.max(dilate, original)
cv2.imwrite('out_5.png', out)

How to change specific pixel value in grayscale image?

I want to change the pixel value of a grayscale image using OpenCV.
Assume that I have a grayscale image and I want to convert all its pixel to 0 value one at a time. So that the resultant image is completely black. I tried this but there is no change in the image:
image = cv2.imread('test_image.png',0)
for i in range(image.shape[0]):
for j in range(image.shape[1]):
image[i, j] = 0
Result:
display the updated image
In most cases, you want to avoid using double for loops to modify pixel values since it is very slow. A better approach is to use Numpy for pixel modification since OpenCV uses Numpy arrays to display images. To achieve your desired result, you can use np.zeros to create a completely black image with the same shape as the original image.
import cv2
import numpy as np
image = cv2.imread("test_image.png", 0)
black = np.zeros(image.shape, np.uint8)
cv2.imshow('image', image)
cv2.imshow('black', black)
cv2.waitKey(0)
For example with a test image. Original (left), result (right)
I would suggest you to always try manipulating the copy of an image so that the image doesn't get affected in the wrong way. Coming to your question, you can do the following:
import cv2
image = cv2.imread('test_image.png',0)
#Creating a copy of the image to confirm right operation is performed on the image.
image_copy = image.copy()
image_copy[:,:] = [0] #Setting all values to 0.

How to analyze only a part of an image?

I want to analyse a specific part of an image, as an example I'd like to focus on the bottom right 200x200 section and count all the black pixels, so far I have:
im1 = Image.open(path)
rgb_im1 = im1.convert('RGB')
for pixel in rgb_im1.getdata():
Whilst you could do this with cropping and a pair of for loops, that is really slow and not ideal.
I would suggest you use Numpy as it is very commonly available, very powerful and very fast.
Here's a 400x300 black rectangle with a 1-pixel red border:
#!/usr/bin/env python3
import numpy as np
from PIL import Image
# Open the image and make into Numpy array
im = Image.open('image.png')
ni = np.array(im)
# Declare an ROI - Region of Interest as the bottom-right 200x200 pixels
# This is called "Numpy slicing" and is near-instantaneous https://www.tutorialspoint.com/numpy/numpy_indexing_and_slicing.htm
ROI = ni[-200:,-200:]
# Calculate total area of ROI and subtract non-zero pixels to get number of zero pixels
# Numpy.count_nonzero() is highly optimised and extremely fast
black = 200*200 - np.count_nonzero(ROI)
print(f'Black pixel total: {black}')
Sample Output
Black pixel total: 39601
Yes, you can make it shorter, for example:
h, w = 200,200
im = np.array(Image.open('image.png'))
black = h*w - np.count_nonzero(ni[-h:,-w:])
If you want to debug it, you can take the ROI and make it into a PIL Image which you can then display. So just use this line anywhere after you make the ROI:
# Display image to check
Image.fromarray(ROI).show()
You can try cropping the Image to the specific part that you want:-
img = Image.open(r"Image_location")
x,y = img.size
img = img.crop((x-200, y-200, x, y))
The above code takes an input image, and crops it to its bottom right 200x200 pixels. (make sure the image dimensions are more then 200x200, otherwise an error will occur)
Original Image:-
Image after Cropping:-
You can then use this cropped image, to count the number of black pixels, where it depends on your use case what you consider as a BLACK pixel (a discrete value like (0, 0, 0) or a range/threshold (0-15, 0-15, 0-15)).
P.S.:- The final Image will always have a dimension of 200x200 pixels.
from PIL import Image
img = Image.open("ImageName.jpg")
crop_area = (a,b,c,d)
cropped_img = img.crop(crop_area)

How to crop elliptical region from image using Python

I have code for rectangle cropping ,Honestly I'm beginner to python
this code was i saw on a site
I'm using PIL library
from PIL import Image
im = Image.open("lenna.png")
crop_rectangle = (50, 50, 200, 200)
cropped_im = im.crop(crop_rectangle)
cropped_im.show()
please help me to crop ellipse or circle region from a image
thank you in advance
Cropping an image to an elliptical or circle region will produce the same results as cropping to a square, if their extents are the same. I am assuming that you also want to mask the image as well as crop?
To do this, create a blank mask PIL Image with the same extent as the original, use PIL.ImageDraw.Draw to draw a polygon onto the image. The mask image should now now have binary pixel values where "1" represents masked. Then simply set all values in the original image to a masked value (i.e. np.nan) where the mask pixel values equal 1 (e.g. original_image[mask == 1] = np.nan).

Categories