I am trying out the Python Imaging Library, but `Image.rotate() seems to crop the image:
from PIL import Image
fn='screen.png'
im = Image.open(fn)
im = im.rotate(-90)
im = im.rotate(90)
im.show()
im.save('cropped.png')
The original image screen.png is:
The cropped image cropped.png is:
The cropping is caused by the 1st rotation and retained in the 2nd rotation.
I am still new to Python, despite trying to become more familiar with it over the years. Is this me doing something wrong with the PIL or is it a bug?
My Python version is:
Python 3.8.8 (default, Mar 4 2021, 21:24:42)
[GCC 10.2.0] on cygwin
Thanks to pippo1980, the solution is to specify expand=1 when invoking rotate():
from PIL import Image
fn='screen.png'
im = Image.open(fn)
im = im.rotate(-90,expand=1)
im = im.rotate(90,expand=1)
im.show()
im.save('cropped.png')
It adjusts the "outer image" width and height to allow an arbitrarily rotated image to fit without cropping. Despite the name, it also shrinks width/height where appropriate.
Related
I was trying to use pytesseract to find the box positions of each letter in an image. I tried to use an image, and cropping it with Pillow and it worked, but when I tried with a lower character size image (example), the program may recognize the characters, but cropping the image with the box coordinates give me images like this. I also tried to double up the size of the original image, but it changed nothing.
img = Image.open('imgtest.png')
data=pytesseract.image_to_boxes(img)
dati= data.splitlines()
corde=[]
for i in dati[0].split()[1:5]: #just trying with the first character
corde.append(int(i))
im=img.crop(tuple(corde))
im.save('cimg.png')
If we stick to the source code of image_to_boxes, we see, that the returned coordinates are in the following order:
left bottom right top
From the documentation on Image.crop, we see, that the expected order of coordinates is:
left upper right lower
Now, it also seems, that pytesseract iterates images from bottom to top. Therefore, we also need to further convert the top/upper and bottom/lower coordinates.
That'd be the reworked code:
from PIL import Image
import pytesseract
img = Image.open('MJwQi9f.png')
data = pytesseract.image_to_boxes(img)
dati = data.splitlines()
corde = []
for i in dati[0].split()[1:5]:
corde.append(int(i))
corde = tuple([corde[0], img.size[1]-corde[3], corde[2], img.size[1]-corde[1]])
im = img.crop(tuple(corde))
im.save('cimg.png')
You see, left and right are in the same place, but top/upper and bottom/lower switched places, and where also altered w.r.t. the image height.
And, that's the updated output:
The result isn't optimal, but I assume, that's due to the font.
----------------------------------------
System information
----------------------------------------
Platform: Windows-10-10.0.16299-SP0
Python: 3.9.1
Pillow: 8.1.0
pytesseract: 4.00.00alpha
----------------------------------------
I'm currently trying to perform a Polar to Cartesian Coordinate Image transformation, to display a raw sonar image into a 'fan-display'.
Initially I have a Numpy Array image of type np.float64, that can be seen below:
After doing some searching, I came across this StackOverflow post Inverse transform an image from Polar to Cartesian in OpenCV with a very similar problem, in which the poster seemed to have solved his/her issue by using the Python Wand library (http://docs.wand-py.org/en/0.5.9/index.html), specifically using their set of Distortion functions.
However, when I tried to use Wand and read the image in, I instead ended up with Wand getting the image below, which seems to be smaller than the original one. However, the weird thing is that img.size still gives the same size number as the original image's shape.
The code for this transformation can be seen below:
print(raw_img.shape)
wand_img = Image.from_array(raw_img.astype(np.uint8), channel_map="I") #=> (369, 256)
display(wand_img)
print("Current image size", wand_img.size) #=> "Current image size (369, 256)"
This is definitely quite problematic as Wand will automatically give the wrong 'fan image'. Is anybody familiar with this kind of problem with the Wand library previously, and if yes, may I ask what is the recommended solution to fix this issue?
If this issue isn't resolved soon I have an alternative backup of using OpenCV's cv::remap function (https://docs.opencv.org/4.1.2/da/d54/group__imgproc__transform.html#ga5bb5a1fea74ea38e1a5445ca803ff121). However the problem with this is that I'm not sure what mapping arrays (i.e. map_x and map_y) to use to perform the Polar->Cartesian transformation, as using a mapping matrix that implements the transformation equations below:
r = polar_distances(raw_img)
x = r * cos(theta)
y = r * sin(theta)
didn't seem to work and instead threw out errors from OpenCV as well.
Any kind of help and insight into this issue is greatly appreciated. Thank you!
- NickS
EDIT I've tried on another image example as well, and it still shows a similar problem. So first, I imported the image into Python using OpenCV, using these lines of code:
import matplotlib.pyplot as plt
from wand.image import Image
from wand.display import display
import cv2
img = cv2.imread("Test_Img.jpg")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.figure()
plt.imshow(img_rgb)
plt.show()
which showed the following display as a result:
However, as I continued and tried to open the img_rgb object with Wand, using the code below:
wand_img = Image.from_array(img_rgb)
display(img_rgb)
I'm getting the following result instead.
I tried to open the image using wand.image.Image() on the file directly, which is able to display the image correctly when using display() function, so I believe that there isn't anything wrong with the wand library installation on the system.
Is there a missing step that I required to convert the numpy into Wand Image that I'm missing? If so, what would it be and what is the suggested method to do so?
Please do keep in mind that I'm stressing the conversion of Numpy to Wand Image quite crucial, the raw sonar images are stored as binary data, thus the required use of Numpy to convert them to proper images.
Is there a missing step that I required to convert the numpy into Wand Image that I'm missing?
No, but there is a bug in Wand's Numpy implementation in Wand 0.5.x. The shape of OpenCV's ndarray is (ROWS, COLUMNS, CHANNELS), but Wand's ndarray is (WIDTH, HEIGHT, CHANNELS). I believe this has been fixed for the future 0.6.x releases.
If so, what would it be and what is the suggested method to do so?
Swap the values in img_rgb.shape before passing to Wand.
img_rgb.shape = (img_rgb.shape[1], img_rgb.shape[0], img_rgb.shape[2],)
with Image.from_array(img_rgb) as img:
display(img)
I am experimenting with openCV and object detection using Python 3.6 on Ubuntu Linux 18.04. I have found this simple Python code at this website that claims to accomplish image detection.
import cv2
import matplotlib.pyplot as plt
import cvlib as cv
from cvlib.object_detection import draw_bbox
im = cv2.imread('/home/gerry/Pictures/guyonstreet.jpg')
bbox, label,conf = cv.detect_common_objects(im)
output_image = draw_bbox(im, bbox, label, conf)
plt.imshow(output_image)
plt.show()
I have installed the necessary libraries without issue as shown on the website. I can run the code without errors. Unfortunately the resulting image fails to show the expected bounding box identifying the object. Below is a screenshot of what the code returned when I ran the experiment on a person. I get similar results when I use an image of fruit.
Why is my code not returning the bounding box identifying the object?
I am trying to create a screen recorder using mss and Opencv in python, the video I am capturing has a very different colours than original computer screen. I tried to find the solution online, Everyone saying it should be fixed using cvtColor() but I already have it in my code.
import cv2
from PIL import Image
import numpy as np
from mss import mss
import threading
from datetime import datetime
`
def thread_recording():
fourcc=cv2.VideoWriter_fourcc(*'mp4v')
#fourcc=cv2.VideoWriter_fourcc(*'XVID')
out=cv2.VideoWriter(vid_file,fourcc,50,(width,height))
mon = {"top": 0, "left": 0, "width":width, "height":height}
sct = mss()
thread1=threading.Thread(target=record,args=(mon,out,sct))
thread1.start()
def record(mon,out,sct):
global recording
recording=True
while recording:
frame= np.array(sct.grab(mon))
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
out.write(frame)
out.release()
the vid_file variable contains a string of output file name with mp4 extension
Screenshot of my screen
Screenshot from recorded video
So, I looked around some more and found that apparently this is a bug in opencv for versions 3.x on wards.then I tried PIL for getting rgb image and removed cvtColor(),but it produced an empty video.I removed both cvtColor() as well as PIL Image as suggested by #ZdaR it again wrote empty video Hence I had to put it back and boom. even if cvtColor() seems like doing nothing, for some unknown reason it has to be there.when you use PIL Image along with cvtColor() it writes the video as expected
from PIL import Image
def record(mon,out,sct):
global recording
recording=True
while recording:
frame=sct.grab(mon)
frame = Image.frombytes('RGB', frame.size, frame.rgb)
frame = cv2.cvtColor(np.array(frame), cv2.COLOR_BGR2RGB)
out.write(np.array(frame))
out.release()
as I am very new to programming, I would really appreciate your help if I missed or overlooked something important
You can do
frameRGB = cv2.cvtColor(frame,cv2.COLOR_RGB2BGR)
Frame is in BGR, and it will work the same as you are only changing R with B where frameRGB is in RGB now. This command will transfer R to B and works to transfer frames from RGB and BGR as well as BGR to RGB. BGR2RGB might be a bug, I have it as well but the command I mentioned works perfectly. That's what I do.
MSS store raw BGRA pixels. Does it work if you change to:
# Grab it
img = np.array(sct.grab(mon))
# Convert from BGRA to RGB
frame = cv2.cvtColor(img, cv2.COLOR_BGRA2RGB)
you should run this command in cmd
pip install opencv-python
I'm trying to open a SAR image from sentinel-1. I can view the tiff file in QGIS, so I know the data is there, but when I go to open and view/show it in python, all of the modules I could use to open the data produce a NaN area, basically insinuating that there is no data in the image. Visualizing the image produces a completely black image, however the shape is correct.
Here is the code where I read in the image:
img = skimage.io.imread('NewData.tif', as_gray = True, plugin = 'tifffile')
with rio.open(r'NewData.tif') as src:
img2 = src.read()
imgMeta = src.profile
print(img)
skimage.io.imshow(img)
Any help would be appreciated.
thank you
The problem is not on the way rasterio or skimage is importing the image, but on the way it is displayed. I am assumign you are working with Calibrated SAR images that ARE NOT converted to the decibel dB scale. Here is the problem, the dynamic range of your data.
The issue here is that by default, the color ramp is not being strech according to the distribution of values in the raster histogram. In QGIS, SNAP or many other EO-related softwares, the color distribution matches the histogram to produce proper visualizations.
Solution: either you make that happen in your code or simply convert your backscatter values to decibel (which is a very common procedure when working with SAR data and produces an almost normal distrubution of the data). The conversion can be done in a EO software or more directly in your imported image with:
srcdB = 10*np.log10(src)
Once done, you can properly display your image:
import rasterio
from rasterio.plot import show
import numpy as np
with rio.open(r'/.../S1B_IW_GRDH_1SDV_20190319T161451_20190319T161520_015425_01CE3C_A401_Cal.tif') as src:
img2 = src.read()
imgMeta = src.profile
srcdB = 10*np.log10(src) # to decibel
show(srcdB, cmap='gray') # show using rasterio