简体   繁体   English

如何在 Dart/Flutter 中使用 Flask Server API 将图像作为请求发布?

[英]How to post an image as a request with Flask Server API in Dart/Flutter?

I want to post a request to a Python-based API that has an image in its body.我想向基于 Python 的 API 发布请求,该 API 的主体中有一个图像。 I have tried to send data with 5 methods:我尝试使用 5 种方法发送数据:

  1. await http.post()等待 http.post()
   final api = Uri.parse("https://e8f628d7.ngrok.io/detections");
   Map<String, dynamic> body = {'images': image};
    final response = await http.post(
      api,
      body: body,
    );

    if (response.statusCode == 200) {
      final responseJson = json.decode(response.body);
      print(responseJson);
    }
  1. Client().post()客户端().post()
     Map<String, dynamic> body = {'images': image};
     var client = new http.Client();
       client.post("https://e8f628d7.ngrok.io/detections",body: body).then((response) {
         print("Post " + response.statusCode.toString());
       });
  1. dio迪奥
  2. MultipartRequest多部分请求
    final api = Uri.parse("https://e8f628d7.ngrok.io/detections");
    var stream = new http.ByteStream(DelegatingStream.typed(image.openRead()));
    var length = await image.length();
    var request = new http.MultipartRequest("POST", api);
    var multipartFileSign = new http.MultipartFile(
        'profile_pic', stream, length,
        filename: path.basename(image.path));
    request.files.add(multipartFileSign);
    // send
    var response = await request.send();
    print(response.statusCode);
    response.stream.transform(utf8.decoder).listen((value) {
      print(value);
    });
  1. Link of [DELETED]First Answer to this question: [DELETED]这个问题的第一个答案的链接:
    if (image == null) return;
    String base64Image = base64Encode(image.readAsBytesSync());
    http.post(api, body: {
      'images': base64Image,
    }).then((res) {
      print(res.statusCode);
      print(json.decode(res.body));
    }).catchError((err) {
      print(err);
    });
  }

I am able to send the image and am getting a 200 success response.我能够发送图像并收到 200 成功响应。 But, I am not sure if the image is getting altered or any problem happens while sending the image as the response is empty whereas it should have some sort of response.但是,我不确定图像是否被更改或在发送图像时发生任何问题,因为响应是空的,而它应该有某种响应。 This is my app.py from with which my server works:这是我的服务器使用的 app.py:

import time
from absl import app, logging
import cv2
import numpy as np
import tensorflow as tf
from yolov3_tf2.models import (
    YoloV3, YoloV3Tiny
)
from yolov3_tf2.dataset import transform_images, load_tfrecord_dataset
from yolov3_tf2.utils import draw_outputs
from flask import Flask, request, Response, jsonify, send_from_directory, abort
import os

# customize your API through the following parameters
classes_path = './data/labels/coco.names'
weights_path = './weights/yolov3.tf'
tiny = False                    # set to True if using a Yolov3 Tiny model
size = 416                      # size images are resized to for model
output_path = './detections/'   # path to output folder where images with detections are saved
num_classes = 80                # number of classes in model

# load in weights and classes
physical_devices = tf.config.experimental.list_physical_devices('GPU')
if len(physical_devices) > 0:
    tf.config.experimental.set_memory_growth(physical_devices[0], True)

if tiny:
    yolo = YoloV3Tiny(classes=num_classes)
else:
    yolo = YoloV3(classes=num_classes)

yolo.load_weights(weights_path).expect_partial()
print('weights loaded')

class_names = [c.strip() for c in open(classes_path).readlines()]
print('classes loaded')

# Initialize Flask application
app = Flask(__name__)

# API that returns JSON with classes found in images
@app.route('/detections', methods=['POST'])
def get_detections():
    raw_images = []
    images = request.files.getlist("images")
    image_names = []
    for image in images:
        image_name = image.filename
        image_names.append(image_name)
        image.save(os.path.join(os.getcwd(), image_name))
        img_raw = tf.image.decode_image(
            open(image_name, 'rb').read(), channels=3)
        raw_images.append(img_raw)

    num = 0

    # create list for final response
    response = []

    for j in range(len(raw_images)):
        # create list of responses for current image
        responses = []
        raw_img = raw_images[j]
        num+=1
        img = tf.expand_dims(raw_img, 0)
        img = transform_images(img, size)

        t1 = time.time()
        boxes, scores, classes, nums = yolo(img)
        t2 = time.time()
        print('time: {}'.format(t2 - t1))

        print('detections:')
        for i in range(nums[0]):
            print('\t{}, {}, {}'.format(class_names[int(classes[0][i])],
                                            np.array(scores[0][i]),
                                            np.array(boxes[0][i])))
            responses.append({
                "class": class_names[int(classes[0][i])],
                "confidence": float("{0:.2f}".format(np.array(scores[0][i])*100))
            })
        response.append({
            "image": image_names[j],
            "detections": responses
        })
        img = cv2.cvtColor(raw_img.numpy(), cv2.COLOR_RGB2BGR)
        img = draw_outputs(img, (boxes, scores, classes, nums), class_names)
        cv2.imwrite(output_path + 'detection' + str(num) + '.jpg', img)
        print('output saved to: {}'.format(output_path + 'detection' + str(num) + '.jpg'))

    #remove temporary images
    for name in image_names:
        os.remove(name)
    try:
        return jsonify({"response":response}), 200
    except FileNotFoundError:
        abort(404)

# API that returns image with detections on it
@app.route('/image', methods= ['POST'])
def get_image():
    image = request.files["images"]
    image_name = image.filename
    image.save(os.path.join(os.getcwd(), image_name))
    img_raw = tf.image.decode_image(
        open(image_name, 'rb').read(), channels=3)
    img = tf.expand_dims(img_raw, 0)
    img = transform_images(img, size)

    t1 = time.time()
    boxes, scores, classes, nums = yolo(img)
    t2 = time.time()
    print('time: {}'.format(t2 - t1))

    print('detections:')
    for i in range(nums[0]):
        print('\t{}, {}, {}'.format(class_names[int(classes[0][i])],
                                        np.array(scores[0][i]),
                                        np.array(boxes[0][i])))
    img = cv2.cvtColor(img_raw.numpy(), cv2.COLOR_RGB2BGR)
    img = draw_outputs(img, (boxes, scores, classes, nums), class_names)
    cv2.imwrite(output_path + 'detection.jpg', img)
    print('output saved to: {}'.format(output_path + 'detection.jpg'))

    # prepare image for response
    _, img_encoded = cv2.imencode('.png', img)
    response = img_encoded.tostring()

    #remove temporary image
    os.remove(image_name)

    try:
        return Response(response=response, status=200, mimetype='image/png')
    except FileNotFoundError:
        abort(404)
if __name__ == '__main__':
    app.run(debug=True, host = '0.0.0.0', port=5000)

I try to send the same image directly through Postman and get the desired response but when I do it with the flutter app, I don't get it.我尝试直接通过 Postman 发送相同的图像并获得所需的响应,但是当我使用 flutter 应用程序发送时,我没有得到它。 Is there any possibility of the image getting altered or modified?图像是否有可能被更改或修改? And, is there any other method in which I can send the image to the API other than the above 3?而且,除了上述 3 种方法之外,还有其他方法可以将图像发送到 API 吗?

You need to make sure that you are using a good version of http .您需要确保您使用的是良好版本的http There was a regression recently that broke multipart form.最近有一个回归破坏了多部分形式。 It's safest for now to hard code the exact version in pubspec.yaml (You might want to look in pubspec.lock to see what version you were using to confirm that it was one of the ones with the error.)现在最安全的是在pubspec.yaml对确切版本进行硬编码(您可能想查看pubspec.lock以查看您使用的版本以确认它是出现错误的版本之一。)

  http: 0.12.0+4

Then try this:然后试试这个:

main() async {
  http.MultipartRequest request = http.MultipartRequest('POST', Uri.parse(url));

  request.files.add(
    await http.MultipartFile.fromPath(
      'images',
      File('kitten1.jpg').path,
      contentType: MediaType('application', 'jpeg'),
    ),
  );

  http.StreamedResponse r = await request.send();
  print(r.statusCode);
  print(await r.stream.transform(utf8.decoder).join());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM