I have build a CNN model and able to classify well. But i want trying to use Django to classify the class of an image when an image is passed in the url. Here are few thing i tried. the prediction function in my apps.py
def prediction(image_loc):
image_path = 'D:/'
image = cv2.imread(os.path.join(image_path,image_loc))
print("image in matrix is ", image)
output = image.copy()
# Pre-Process the image for classification
image = cv2.resize(image, (96, 96))
image = image.astype("float") / 255.0
image = img_to_array(image)
image = np.expand_dims(image, axis=0)
# Load the trained convolutional neural network and the label binarizer
print("[INFO] Loading Model...")
model_RP = load_model(os.path.join(os.getcwd(), "model\cnn_model_RP.hdf5"))
lb_path = os.path.join(os.getcwd(),"model\labelbin_RP")
lb_RP = pickle.loads(open(lb_path, "rb").read())
print("[INFO] Model Loading Complete.")
# Classify the input image
print("[INFO] classifying image...")
proba = model_RP.predict(image)[0]
idx = np.argmax(proba)
label = lb_RP.classes_[idx]
#we will mark our prediction as "correct" of the input image filename contains the predicted label text
#(obviously this makes the assumption that you have named your testing image files this way)
filename = image_loc[image_loc.rfind(os.path.sep) + 1:]
correct = "correct" if filename.rfind(label) != -1 else "incorrect"
# Build the label and draw the label on the image
label = "{}: {:.2f}% ({})".format(label, proba[idx] * 100, correct)
output = imutils.resize(output, width=400)
cv2.putText(output, label, (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2)
# show the output image
print("[INFO] {}".format(label))
#plt.imshow(output)
#plt.show()
#return(plt.show())
return(label) #- WORKING
#return HttpResponse(output, content_type = 'image/png')
#resp = HttpResponse("", content_type = 'image/png')
#resp.write('output')
#return resp
If i return just the label it works, below is Code snippet from my apps.py
label = "{}: {:.2f}% ({})".format(label, proba[idx] * 100, correct)
return (label)
2.a Here is the problem. I am trying to return the image as well with label on it. which i am not successful.
label = "{}: {:.2f}% ({})".format(label, proba[idx] * 100, correct)
output = imutils.resize(output, width=400)
cv2.putText(output, label, (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2)
return HttpResponse(output, content_type = 'image/png')
2.b Here is the 2nd approach to return the image, unfortunately failed.
label = "{}: {:.2f}% ({})".format(label, proba[idx] * 100, correct)
output = imutils.resize(output, width=400)
cv2.putText(output, label, (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2)
resp = HttpResponse("", content_type = 'image/png')
resp.write('output')
return resp
Here is my views.py
#api_view(['GET']) # Decorator
def call_model(request):
#if request.method == 'GET':
# sentence is the query we want to get the prediction for
params = request.GET.get('image_loc')
# predict method used to get the prediction
resp = prediction(image_loc = params)
# returning JSON response
return Response(resp)
Stack trace of error, when i run the below on the browser.
http://127.0.0.1:8000/model/img?format=json&image_loc=bulbasaur_plush.png
TypeError at /model/img
<HttpResponse status_code=200, "image/png"> is not JSON serializable
Request Method: GET
Request URL: http://127.0.0.1:8000/model/img?format=json&image_loc=bulbasaur_plush.png
Django Version: 2.2.12
Exception Type: TypeError
Exception Value:
<HttpResponse status_code=200, "image/png"> is not JSON serializable
Exception Location: C:\Anaconda3\envs\tf35\lib\json\encoder.py in default, line 179
Python Executable: C:\Anaconda3\envs\tf35\python.exe
Python Version: 3.5.5
Python Path:
['D:\\Discern\\Term 3\\deploy',
'C:\\Anaconda3\\envs\\tf35\\python35.zip',
'C:\\Anaconda3\\envs\\tf35\\DLLs',
'C:\\Anaconda3\\envs\\tf35\\lib',
'C:\\Anaconda3\\envs\\tf35',
'C:\\Users\\prade\\AppData\\Roaming\\Python\\Python35\\site-packages',
'C:\\Anaconda3\\envs\\tf35\\lib\\site-packages',
'C:\\Anaconda3\\envs\\tf35\\lib\\site-packages\\win32',
'C:\\Anaconda3\\envs\\tf35\\lib\\site-packages\\win32\\lib',
'C:\\Anaconda3\\envs\\tf35\\lib\\site-packages\\Pythonwin']
Server time: Fri, 29 May 2020 04:35:18 +0000
Tried to looks at similar posts but they are related to text, so could not get my issue solved.
Could someone help please.
It looks like resp is a HttpResponse object (can't tell more, you did not gave code for prediction).
You have to make something JSON serializable within the Response() constructor (usually a dict, or a list, with only string / int / boolean).
(BTW, the #api_view decorator of Django Rest Framework is outdated, #action is prefered with last version)
Related
I have a predictor that works successfully when run on a local container, but when that container is pushed to the Artifact Registry, and imported to a Vertex AI model, and run in Batch Prediction mode, it returns an empty prediction file and an error file that simply says ('ValueError', 1)
The request is made using Flask.
code (main.py) is
if 'AIP_HEALTH_ROUTE' in os.environ:
AIP_HEALTH_ROUTE = os.environ['AIP_HEALTH_ROUTE']
else:
AIP_HEALTH_ROUTE = '/health'
if 'AIP_PREDICT_ROUTE' in os.environ:
AIP_PREDICT_ROUTE = os.environ['AIP_PREDICT_ROUTE']
else:
AIP_PREDICT_ROUTE = '/predict'
#app.route(AIP_HEALTH_ROUTE, methods=['GET'])
def health():
response = {"message": "OK", "code": "SUCCESS"}
return make_response(jsonify(response), 200)
#app.route(AIP_PREDICT_ROUTE, methods=['POST'])
def predict():
try:
instances = pd.DataFrame(request.json.get("instances"))
# creates a model using model and encoders stored at given GCS location
model = model_active.CustomPredictor('datascience-modelartifacts/my-model/actives')
processed_data = model.process_score_data(instances)
predictions = model.predict(processed_data)
response = {"predictions": predictions}
status = 200
except Exception as e:
response = {"error": str(e)}
status = 500
return make_response(jsonify(response), status)
For local testing, the data looks like:
dat = {"instances": [
{"F1": 1000854828492, "F2": 3000076437878, "F3": 19.99, ...},
{"F1": 1000222326963, "F2": 3000127917915, "F3": 19.99, ...},
... ]}
I call this with
import requests
url = 'http://localhost:5000/predict'
headers = {'content-type': 'application/json', 'Accept-Charset': 'UTF-8'}
r = requests.post(url, json=dat, headers=headers)
and in this case everything works as expected (I get a list of predicted classes returned).
I can successfully deploy this model as an endpoint and provide this data as test and get predictions returned.
However, for Vertex batch prediction (which is what I ultimately want to enable since we only need this model once a month), I have tried providing this data as both JSONL and CSV and I keep receiving output with no successful predictions and an error file that simply says ('ValueError', 1)
Does anyone have any suggestions what this error means and what is causing it?
I'm trying to test multiple image upload to my server. Here is the serializer:
class ImageSerializer(serializers.ModelSerializer):
image = serializers.ListField(
child=serializers.ImageField(allow_empty_file=True)
)
ImageFactory:
def get_image():
image = Image.new("RGB", (2000, 2000))
file = tempfile.NamedTemporaryFile(suffix=".jpg")
image.save(file)
return file
Test:
def test_upload_multiple_images(self):
self.image = get_image()
with open(self.image.name, "rb") as file:
payload = {
"image": [file, file]
}
response = self.client.post(
reverse("gallery-list", args=[self.item.pk]),
data=payload,
format="multipart"
)
When testing via Postman, images from the array are saved correctly. However when using the test case, I get the following message from the response:
{'image': [{'message': 'The submitted file is empty.', 'code': 'empty'}]}
Before adding allow_empty_file=True, there were two of those messages being returned.
Has anyone got any idea why that would happen?
The problem here is that you're sending the same Image object to the database to be saved twice. Once the first Image object has been decoded to a file to be saved in the database, the Image object will become unreadable, and since its the same object as the second, an error will be thrown.
So if you send the same Image object as two different items, only the first one will be readable. To avoid this you'll have to send two different image objects.
Your ImageFactory can be refactored to:
def get_image(count=1):
images = []
for i in list(range(count)):
file = io.BytesIO()
image = Image.new('RGBA', size=(100, 100), color=(155, 0, 0))
image.save(file, 'png')
file.name = 'test.png'
file.seek(0)
images.append(file)
return images[0] if count == 1 else images
and your Test:
def test_upload_multiple_images(self):
self.images = get_image(2)
payload = {
"image": self.images
}
response = self.client.post(
reverse("gallery-list", args=[self.item.pk]),
data=payload,
format="multipart"
)
I am trying to save my photo recive from my form changed by PIL in the ImageField field.
file = cd['custom_img'] #get my file from my form
#resize image
image = Image.open(file)
(w, h) = image.size
if (w > 1000):
h = int(h * 1000. / w)
w = 1000
image = image.resize((w, h), Image.ANTIALIAS)
rgb_image = image.convert('RGB')
#save in object
thumb_io = BytesIO() #create a BytesIO object
rgb_image.save(thumb_io, 'JPEG', quality=80) # save image to BytesIO object
thumbnail = File(thumb_io) #create a django friendly File object
owner.basic_img = thumbnail
owner.save()
My code does not return any result. Nothing is still written in my field.
My attempts:
1.) Checking if the file will be saved
I tried to check if my picture was saved correctly. Everything works well. A modified photo is created from the form sent.
#resize image
print(file)
image = Image.open(file)
print(image)
(w, h) = image.size
if (w > 1000):
h = int(h * 1000. / w)
w = 1000
image = image.resize((w, h), Image.ANTIALIAS)
rgb_image = image.convert('RGB')
#save
rgb_image.save('my_image.jpg')
2.) I tried to save the photo according to this tutorial
thumbnail = File(thumb_io, name=image.name) # create a django friendly File object
My code raises an error here
AttributeError: 'Image' object has no attribute 'name'
How can I save my resize image by PIL in my view?
I just started to use Django, and I want to create a button that will initiate a PDF download with a header and a footer. for the PDF I use Reportlab. In the Django documentation, they say to use the Canvas object, but I cannot add a footer and a header with canvas. Can anyone give me a piece of code that will return a response from a view in Django with a PDF download with footer and header?
thank you!
Extending BaseDocTemplate allows you to define a Frame contained within a PageTemplate. Flowables are used in the frame so your content can flow over to other pages. The header and footer are just strings of text placed on the Canvas outside of the frame. saveState() and restoreState() have to be used when defining a header and footer so that it repeats on each page of your pdf.
class HeaderFooterTemplate(BaseDocTemplate):
def __init__(self, filename, **kwargs):
self.report_title = kwargs['report_title']
self.pagesize = kwargs['pagesize']
BaseDocTemplate.__init__(self, filename, **kwargs)
main_frame = Frame(
0, 0, self.pagesize[0], self.pagesize[1], topPadding=25, bottomPadding=18, id='main_frame')
template = PageTemplate(id='frame', frames=[main_frame], onPage=self.header_footer)
self.addPageTemplates([template])
def header_footer(self, canv, doc):
canv.saveState()
canv.setPageSize(doc.pagesize)
canv.setTitle(doc.title)
# header
canv.drawCentredString(doc.pagesize[0] / 2, doc.pagesize[1] - 15, self.report_title)
# footer
date_printed = 'Date Printed: ' + dateformat.format(timezone.localtime(timezone.now()), 'Y-m-d f A')
footer_date = canv.beginText(0, 2)
footer_date.textLine(date_printed)
canv.drawText(footer_date)
canv.restoreState()
class PdfTest:
def __init__(self):
self.buffer = BytesIO()
self.pagesize = letter
self.story = []
def build_pdf(self, filename):
"""
Get the value of the BytesIO buffer and write it to the response.
:param filename: name of the file when downloading
"""
pdf = self.buffer.getvalue()
self.buffer.close()
if pdf:
response = HttpResponse(pdf, content_type='application/pdf')
content = 'inline; filename="%s"' % filename
response['Content-Disposition'] = content
return response
def draw(self):
style = styles["Normal"]
for i in range(100):
bogustext = ("This is Paragraph number %s. " % i) *20
p = Paragraph(bogustext, style)
self.story.append(p)
self.story.append(Spacer(1,0.2*inch))
doc = HeaderFooterTemplate(self.buffer, pagesize=self.pagesize, report_title='Test Header Footer PDF')
doc.build(self.story)
return self.build_pdf('test.pdf')
class PdfView(View):
def get(self, request):
pdf = PdfTest()
return pdf.draw()
I use Django ImageKit to process/crop uploaded photos. I added my own custom processor to add text to the photo (like watermark):
# ./example/processors.py
from django.conf import settings
from PIL import Image, ImageDraw, ImageFont
_default_font = ImageFont.truetype(settings.TEXT_OVERLAY_FONT_REGULAR, 24)
def add_text_overlay(image, text, font=_default_font):
rgba_image = image.convert('RGBA')
text_overlay = Image.new('RGBA', rgba_image.size, (255, 255, 255, 0))
image_draw = ImageDraw.Draw(text_overlay)
text_size_x, text_size_y = image_draw.textsize(text, font=font)
text_xy = ((rgba_image.size[0] / 2) - (text_size_x / 2), (rgba_image.size[1] / 2) - (text_size_y / 2))
image_draw.text(text_xy, text, font=font, fill=(255, 255, 255, 255))
image_with_text_overlay = Image.alpha_composite(rgba_image, text_overlay)
return image_with_text_overlay
class TextOverlayProcessor(object):
def __init__(self, text='Lorem ipsum dolor sit amet'):
"""
:param text: The overlay text, string.
"""
self.text = text
def process(self, img):
return add_text_overlay(image=img, text=self.text)
But how to transfer value from field to the custom ImageKit processor inside the model? Something like this:
# ./example/models.py
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill
from .processors import TextOverlayProcessor
class Example(models.Model):
description = models.CharField('Description', ...)
image = models.ImageField('Picture', default=None)
image_800x800 = ImageSpecField(
source='image',
processors=[
ResizeToFill(800, 800),
TextOverlayProcessor(text=self.description) # but `self` is wrong and raise error
],
format='JPEG',
options={'quality': 100}
)
...
I will be glad to explanatory comments and/or use cases.
The short answer is https://stackoverflow.com/a/27914831/6543526
From official docs:
Often, when using an ImageSpecField, you may want the spec to vary
based on properties of a model. (For example, you might want to store
image dimensions on the model and then use them to generate your
thumbnail.) Now that we know how to access the source image from our
spec, it’s a simple matter to extract its model and use it to create
our processors list. In fact, ImageKit includes a utility for getting
this information.