I'm trying to detect width and height of an image before saving it to the database and S3. The image is in bytes.
This is an example of an image before saved to Django ImageField:
NOTE: I don't want to use ImageFields height_field and width_field as it slows down the server tremendously for some reason so I want to do it manually.
The image is downloaded using requests:
def download_image(url):
r = requests.get(url, stream=True)
r.raw.decode_content = True
return r.content
To get the width/height of an image from a binary string, you would have to try to parse the binary string with an image library. The easiest one for the job would be pillow.
import requests
from PIL import Image
import io
def download_image(url):
r = requests.get(url, stream=True)
r.raw.decode_content = True
return r.content
image_url = "https://picsum.photos/seed/picsum/300/200"
image_data = download_image(image_url)
image = Image.open(io.BytesIO(image_data))
width = image.width
height = image.height
print(f'width: {width}, height: {height}')
width: 300, height: 200
Related
I am trying to work with IMDb API. My code thus far is
import http.client
import json
import requests
conn = http.client.HTTPSConnection("imdb-api.com", 443)
payload = ''
headers = {'User-agent': 'Chrome/95.0'}
conn.request("GET", "https://imdb-api.com/en/API/MostPopularMovies/<API_Key>",headers=headers)
res = conn.getresponse()
data = res.read()
convertedDict = json.loads(data.decode("utf-8"))
imagepath = r'venv/files/image.jpeg'
req = requests.get(convertedDict['items'][0]['image'], headers=headers)
with open(imagepath, 'wb') as file:
file.write(req.content)
This allows me to download the image of the first popular movie, however, the image size is really small. This is the link that I am downloading. I know that if I get rid of everything after # the image will become a lot larger. Is there a way to edit the link such that I can drop everything after # and even edit the numbers after UX with code?
Everything I try to do with string or URL operations give's me an error
https://m.media-amazon.com/images/M/MV5BZWMyYzFjYTYtNTRjYi00OGExLWE2YzgtOGRmYjAxZTU3NzBiXkEyXkFqcGdeQXVyMzQ0MzA0NTM#._V1_UX128_CR0,3,128,176_AL_.jpg
Thank you in advance
Explanation
(code example below)
Here's how to get a bigger image of the size you want. Given this URL,
https://m.media-amazon.com/images/M/MV5BZWMyYzFjYTYtNTRjYi00OGExLWE2YzgtOGRmYjAxZTU3NzBiXkEyXkFqcGdeQXVyMzQ0MzA0NTM#._V1_UX128_CR0,3,128,176_AL_.jpg
There's a substring of it:
UX128_CR0,3,128,176
This has three important parts:
The first 128 resizes the image by width, keeping ratio
The second 128 controls the container width that the image appears in
176 controls the container height that the image appears in.
So, we can view the structure like this:
UX<image_width>_CR0,3,<container_width>,<container_height>
As an example, to double the image size:
UX256_CR0,3,256,352_AL_.jpg
(Click here to see: https://m.media-amazon.com/images/M/MV5BZWMyYzFjYTYtNTRjYi00OGExLWE2YzgtOGRmYjAxZTU3NzBiXkEyXkFqcGdeQXVyMzQ0MzA0NTM#.V1_UX256_CR0,3,256,352_AL.jpg
Update: Example of how you might do it in Python.
import re
resize_factor = 2 # Image size multiple
url = "https://m.media-amazon.com/images/M/MV5BZWMyYzFjYTYtNTRjYi00OGExLWE2YzgtOGRmYjAxZTU3NzBiXkEyXkFqcGdeQXVyMzQ0MzA0NTM#._V1_UX128_CR0,3,128,176_AL_.jpg"
#
# resize_factor : Image size multiplier (e.g., resize_factor = 2 doubles the image size, positive integer only)
# url : full URL of the image
# return : string of the new URL
#
def getURL(resize_factor, url):
# Regex for pattern matching relevant parts of the URL
p = re.compile(".*UX([0-9]*)_CR0,([0-9]*),([0-9]*),([0-9]*).*")
match = p.search(url)
if match:
# Get the image dimensions from the URL
img_width = str(int(match.group(1)) * resize_factor)
container_width = str(int(match.group(3)) * resize_factor)
container_height = str(int (match.group(4)) * resize_factor)
# Change the image dimensions
result = re.sub(r"(.*UX)([0-9]*)(.*)", r"\g<1>"+ img_width +"\g<3>", url)
result = re.sub(r"(.*UX[0-9]*_CR0,[0-9]*,)([0-9]*)(.*)", r"\g<1>"+ img_width +"\g<3>", result)
result = re.sub(r"(.*UX[0-9]*_CR0,[0-9]*,[0-9]*,)([0-9]*)(.*)", r"\g<1>"+ container_height +"\g<3>", result)
return result
#
# Test
#
print (getURL(resize_factor,url))
Edit: Typo
import requests
import cv2
frame=cv2.imread('C:\\Users\\aaa\\Downloads\\abc.jpg')
url = 'https://app.nanonets.com/api/v2/ObjectDetection/Model/4729a79f-ab19-4c1b-8fe9'
data = {'file': open('C:\\Users\\aaa\\Downloads\\abc.jpg', 'rb')}
response = requests.post(url, auth=requests.auth.HTTPBasicAuth('S5zsN-yFZJxRH9tMwsaHUCxJg3dZaDWj', ''), files=data)
print (type(response))
print(response)
I uploaded an image for object detection. I got the response like this.
{"message":"Success","result":[{"message":"Success","input":"abc.jpg","prediction":[{"label":"car","xmin":411,"ymin":332,"xmax":585,"ymax":462,"score":0.99097943},{"label":"car","xmin":496,"ymin":170,"xmax":592,"ymax":248,"score":0.96399206},{"label":"car","xmin":223,"ymin":147,"xmax":294,"ymax":202,"score":0.9383388},{"label":"car","xmin":164,"ymin":130,"xmax":230,"ymax":175,"score":0.8968652},{"label":"car","xmin":448,"ymin":489,"xmax":623,"ymax":540,"score":0.8311123}],"page":0,"request_file_id":"5a8549f1-fb2c-487a-83b5-234608b3168b","filepath":"uploadedfiles/4729a79f-ab19-fac0fb807e6d/PredictionImages/53207.jpeg"}]}
I want to make a box in the image with the given coordinates.
import requests
import cv2
import math
from PIL import Image, ImageDraw
import json
frame=cv2.imread('C:\Users\aaa\Downloads\abc.jpg')
url = 'https://app.nanonets.com/api/v2/ObjectDetection/Model/4729a79f-ab19-4c1b-8fe9'
data = {'file': open('C:\Users\aaa\Downloads\abc.jpg', 'rb')}
response = requests.post(url, auth=requests.auth.HTTPBasicAuth('S5zsN-yFZJxRH9tMwsaHUCxJg3dZaDWj', ''), files=data)
predictions = json.loads(response.text)['result'][0]['prediction']
img = Image.open('C:\Users\aaa\Downloads\abc.jpg')
img1 = ImageDraw.Draw(img)
for prediction in predictions:
shape = [(prediction['xmin'], prediction['ymin']), (prediction['xmax'], prediction['ymax'])]
img1.rectangle(shape, fill ="# ffff33", outline ="red")
img.show()
I have a snippet that reads my images locally (returns binary), i.e:
image = 'car.jpg'
with open(image, 'rb') as image_file:
content = image_file.read()
I'm trying to recreate the same but with images that are hosted on the internet, I have tried with the following but I've had no luck.
from urllib.request import urlopen
from PIL import Image
import io
url = 'https://somewebsite.com/fm-01/car.jpg'
image = urlopen(url)
image_file = io.BytesIO(image.read())
im = Image.open(image_file)
im = im.tobytes()
EDIT ...
Same exact image, one on google cloud storage and the other one locally.
They have different bytes when opening them.
with open('car.jpg','rb') as image_file:
content = image_file.read()
print(len(content))
size : 234712
url = 'https://storage.googleapis.com/fm-01/car.jpg'
img = Image.open(urlopen(url))
image = img.tobytes()
print(len(image))
size : 1077600
It is simple as:
from urllib.request import urlopen
url = 'https://somewebsite.com/fm-01/car.jpg'
img = urlopen(url).read()
You have not understood the comment I made explaining exactly this under Mikhail's answer.
The 234,712 bytes is the size of the JPEG-encoded data in the disk file - it includes the image height, width, date, GPS coordinates, camera manufacturer and the all the pixels of the image DCT-compressed into a JPEG.
The 1,077,600 bytes is the size of the array you will need to create in memory to hold the uncompressed red, green and blue pixels in, say 898x400 pixels at 3 bytes (1 red, 1 green and 1 blue) per pixel.
898 * 400 * 3 = 1077600
I receive IOError: cannot identify image for the code given below for when I deploy app engine but it works perfectly for localhost.
I creates first image but fails the second one on production but success both on localhost
In my app.yaml:
libraries:
- name: PIL
version: "1.1.7"
I tried also with
libraries:
- name: PIL
version: latest
The relevant code:
class UploadFile(webapp2.RequestHandler):
def post(self):
data = self.request.body
values = self.request.POST.itervalues()
files = [v for v in values if isinstance(v, cgi.FieldStorage)]
img_data = data
dataBytesIO = io.BytesIO(img_data) #log label "toto"
my_img = Image.open(files[0].file)
my_img.thumbnail((500, 500), Image.ANTIALIAS)
thumb_io = BytesIO()
my_img.save(thumb_io, my_img.format)
thumbnail_filename_input = create_file(self, thumb_io.getvalue(), "room_picture_thumbnail_" + "somename", files[0].type)
size = 1000, 1000 #log label "titi"
my_img_big = Image.open(files[0].file) #!!! Fails on production but works on localhost
width, height = my_img_big.size
if width > 1000 or height > 1000:
my_img_big.thumbnail(size,Image.ANTIALIAS)
thumb_io2 = BytesIO()
my_img_big.save(thumb_io2, my_img_big.format)
filename_input = create_file(self, thumb_io2.getvalue(), "room_picture_" +"somename", files[0].type)
gives error below:
my_img_big = Image.open(files[0].file)
File "/base/alloc/tmpfs/dynamic_runtimes/python27g/b3d733487011db10/python27/python27_lib/versions/third_party/PIL-1.1.7/PIL/Image.py", line 1980, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
And log snap shot at app engine stackdriver debug:
files
[0]
fp
<type '_io.BytesIO'>
disposition_options
file
<type 'cStringIO.StringO'>
innerboundary
''
done
1
disposition
'form-data'
qs_on_post
None
strict_parsing
0
outerboundary
'----WebKitFormBoundarykEX5mAPk1xmDW6B3' # only this line differs between two -> '----WebKitFormBoundaryZxbkkzZRFdunz9Fr' at log labels "toto" and "titi"
name
u'aa.png'
_FieldStorage__file
None
list
None
filename
u'/frpy/uploadFile'
keep_blank_values
True
headers
length
-1
type_options
type
'image/png'
I even tried to below code on app engine prod from local with
remote_api_stub.ConfigureRemoteApiForOAuth(
'{}.appspot.com'.format(project_id),
'/_ah/remote_api')
and code:
import urllib2 as urllib
import io
fd = urllib.urlopen("https://i.stack.imgur.com/mVt7n.jpg?s=328&g=1")
image_file = io.BytesIO(fd.read())
im = Image.open(image_file)
im.thumbnail((500, 500), Image.ANTIALIAS)
thumb_io = BytesIO()
im.save(thumb_io, im.format)
size = 1000, 1000
my_img_big = Image.open(image_file)
width, height = my_img_big.size
if width > 1000 or height > 1000:
my_img_big.thumbnail(size,Image.ANTIALIAS)
thumb_io2 = BytesIO()
my_img_big.save(thumb_io2, my_img_big.format)
operating twice on image_file works goood.
What could be issue works on localhost but fails on prod?
Tip: my_img.close() works on localhost but not on prod, note also when I do to figure out files[0].file.close() on localhost it gives me ValueError: I/O operation on closed file so the issue is not related being closed
files[0].file.seek(0)
is the answer, I should rewind it :)
i want to take screenshot and crop only the captcha image, im write this code : http://pastebin.com/Hqau6kRD :
elem = driver.find_element_by_css_selector("#imagecpt")
loc = elem.location
size = elem.size
left = loc['x']
top = loc['y']
width = size['width']
height = size['height']
box = (int(left), int(top), int(left+width), int(top+height))
screenshot = driver.get_screenshot_as_png()
img = Image.open(StringIO.StringIO(screenshot))
area = img.crop(box)
area.save('screenshot.png', 'PNG')
the image saved is complete black, where im wrong ?
Yeah. For Python3 it will be like:
...
from io import BytesIO
...
screenshot = driver.get_screenshot_as_base64()
img = Image.open(BytesIO(base64.b64decode(screenshot))
...
I'm assuming you are using the Image module from PIL library.
Try getting the base64 value, decode it and then pass it as a parameter to the open() method.
...
screenshot = driver.get_screenshot_as_base64()
img = Image.open(StringIO.StringIO(base64.b64decode(screenshot))
...