使用LineBot开发目标检测应用遇类型错误:expected bytes, HTTPResponse found
LineBot目标检测应用HTTP图片URL报错处理
报错信息
[2022-11-23 19:13:12,335] ERROR in app: Exception on /callback [POST] Traceback (most recent call last): File "C:\officiallandprice\myproject\myenv\lib\site-packages\flask\app.py", line 2525, in wsgi_app response = self.full_dispatch_request() File "C:\officiallandprice\myproject\myenv\lib\site-packages\flask\app.py", line 1822, in full_dispatch_request rv = self.handle_user_exception(e) File "C:\officiallandprice\myproject\myenv\lib\site-packages\flask\app.py", line 1820, in full_dispatch_request rv = self.dispatch_request() File "C:\officiallandprice\myproject\myenv\lib\site-packages\flask\app.py", line 1796, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) File "part1deploy_3.py", line 55, in callback handler.handle(body, signature) File "C:\officiallandprice\myproject\myenv\lib\site-packages\linebot\webhook.py", line 259, in handle self.__invoke_func(func, event, payload) File "C:\officiallandprice\myproject\myenv\lib\site-packages\linebot\webhook.py", line 271, in __invoke_func func(event) File "part1deploy_3.py", line 201, in handle_content_message text_detected1=text_detected(user.user_id) File "part1deploy_3.py", line 81, in text_detected image = vision.Image(content=input_file) File "C:\officiallandprice\myproject\myenv\lib\site-packages\proto\message.py", line 604, in __init__ super().__setattr__("_pb", self._meta.pb(**params)) TypeError: expected bytes, HTTPResponse found 127.0.0.1 - - [23/Nov/2022 19:13:12] "POST /callback HTTP/1.1" 500 -
问题根源
- Google Cloud Vision API的参数要求:
vision.Image(content=...)的content参数必须传入字节类型的图片原始数据,而urllib.request.urlopen()返回的是HTTPResponse响应对象,并非字节数据,这是触发报错的直接原因。 - PIL读取的潜在问题:即使Vision API不报错,后续
Image.open(input_file)也会失败——HTTPResponse的数据流在第一次读取后指针会移到末尾,第二次读取时无法获取有效内容。
修正后的代码
修改text_detected函数,先将URL对应的图片读取为字节数据,再分别用于Vision API和PIL处理:
def text_detected(user_id): # 读取图片为字节数据 url = 'https://storage.googleapis.com/img_platecapture/{}.jpg'.format(user_id) with urllib.request.urlopen(url) as response: img_bytes = response.read() # 传入字节数据给Vision API image = vision.Image(content=img_bytes) response = vision_client.text_detection(image=image) if response.error.message: raise Exception( '{}\nFor more info on error messages, check: ' 'https://cloud.google.com/apis/design/errors'.format( response.error.message)) # 用字节数据创建PIL Image对象(需用BytesIO包装) from io import BytesIO img = Image.open(BytesIO(img_bytes)) draw = ImageDraw.Draw(img) font = ImageFont.truetype("simsun.ttc", 18) # 补充原代码遗漏的bound变量定义 for text in response.text_annotations[1::]: ocr = text.description bound = text.bounding_poly draw.text((bound.vertices[0].x-25, bound.vertices[0].y-25), ocr, fill=(255,0,0), font=font) draw.polygon( [ bound.vertices[0].x, bound.vertices[0].y, bound.vertices[1].x, bound.vertices[1].y, bound.vertices[2].x, bound.vertices[2].y, bound.vertices[3].x, bound.vertices[3].y, ], None, 'yellow', ) texts=response.text_annotations a=str(texts[0].description.split()) b=re.sub(u"([^\u4e00-\u9fa5\u0030-u0039])","",a) b1="".join(b) print("偵測到的地址為:",b1) return b1
关键说明
- Vision API必须用字节数据:这是Google Cloud Vision API的硬性规定,
content参数需要直接传入图片的原始字节流,用于API解析图片内容。 - PIL的处理方式:PIL的
Image.open()可以接受字节流,但需要用BytesIO将字节数据包装成类文件对象,才能被PIL正确识别读取。 - 原代码的其他问题:原循环中使用了未定义的
bound变量,需补充bound = text.bounding_poly,否则会触发NameError。
内容的提问来源于stack exchange,提问作者april
相关产品推荐
相关产品推荐

