Flask部署图像识别的服务但Android端无法连接服务器

我在云服务器上用Flask和tornado部署了一个用于图像识别的服务,如果直接在浏览器输入ip地址+端口号的话,可以访问指定的网页,并且上传图片点击计算,服务器端都有响应,返回该图片的分类以及相似概率等数据。但是在安卓端上即使ip地址设置正确,点击上传图片也会显示“未连接服务器”。希望有大佬可以帮忙解决下这个问题,代码放在下面了。


服务器端代码:

(老师给的陈年老代码了……python2环境下的……)

import os
import json
import time
import cPickle
import random
import datetime
import logging
import flask
import werkzeug
import optparse
import tornado.wsgi
import tornado.httpserver
import numpy as np
import pandas as pd
from PIL import Image
import cStringIO as StringIO
import urllib
import glob
import cv2
#import lmdb
import caffe
from caffe.proto import caffe_pb2
from urllib import urlencode
from urllib import quote
from class_labels import labels
import pymysql
from werkzeug.utils import secure_filename

DATA_FOLDER = '/input/cat-flask/ResNet-50'
UPLOAD_FOLDER = '/input/cat-flask/uploads'
THUMBNAIL_FOLDER = '/input/cat-flask/thumbnails'
ALLOWED_IMAGE_EXTENSIONS = set(['png', 'bmp', 'jpg', 'jpe', 'jpeg', 'gif'])
IMAGE_WIDTH = 224
IMAGE_HEIGHT = 224

baseurl = 'http://bob.geeekvr.com'

# Obtain the flask app object
app = flask.Flask(__name__)

@app.route('/')
def index():
    return flask.render_template('index.html', has_result=False)

@app.route('/images/<path:path>')
def send_images(path):
    return flask.send_from_directory('images', path)

@app.route('/uploads/<path:path>')
def send_uploads(path):
    return flask.send_from_directory('uploads', path)

@app.route('/thumbnails/<path:path>')
def send_thumbnails(path):
    return flask.send_from_directory('thumbnails', path)

@app.route('/classify_upload', methods=['POST'])
def classify_upload():
    try:
	sdkurl = flask.request.form.get('sdkurl', type=str, default=baseurl)
        imagefile = flask.request.files['imagefile']
        filename_ = (datetime.datetime.now()).strftime("%Y%m%d%H%M%S") + '_' + \
            secure_filename(imagefile.filename)
        filename = os.path.join(UPLOAD_FOLDER, filename_)
        imagefile.save(filename)
        logging.info('Saving to %s.', filename)
        image = cv2.imread(filename, cv2.IMREAD_COLOR)
	res = cv2.resize(image, (64,64), interpolation=cv2.INTER_CUBIC)
	thumbnail = os.path.join(THUMBNAIL_FOLDER, filename_)
	cv2.imwrite(thumbnail, res)
    except Exception as err:
        logging.info('Uploaded image open error: %s', err)
	result = {"errcode":1, "errmsg":"Cannot open uploaded image."}
	return flask.jsonify(result)

    result = app.clf.classify_image(image, sdkurl)
    if result["errcode"] == 0:
	try:
		result["imgurl"] = sdkurl+"/uploads/"+urllib.quote(filename_)
		source = flask.request.form.get('source', type=str, default='-1')
		usertoken = flask.request.form.get('usertoken', type=str, default='')
		catsid0 = -1;
		catsid1 = -1;
		catsid2 = -1;
		if result["count"] > 0:
			catsid0 = result["result"][0]["id"]
                if result["count"] > 1:
                        catsid1 = result["result"][1]["id"]
                if result["count"] > 2:
                        catsid2 = result["result"][2]["id"]

		db = pymysql.connect( \
			"localhost",\
			"kando",\
			"1997416",\
			"CAT777")
		cursor = db.cursor()
		sql = "insert into cats_image( \
		       uid, filename, thumbnail, source,\
		       catsid0, catsid1, catsid2,\
		       createtime) values(%s, '%s', '%s', %s, %s, %s, %s, now())" % \
		       (0, "uploads/"+filename_, "thumbnails/"+filename_, source, \
		       catsid0, catsid1, catsid2)
		print(sql)
		try:
			cursor.execute(sql)
			db.commit()
		except Exception as err:
			print(err)
			db.rollback()
		db.close()

	except Exception as err:
		print(err)
    else:
	print("errcode="+str(errcode))
    return flask.jsonify(result)

def embed_image_html(image):
    """Creates an image embedded in HTML base64 format."""
    image_pil = Image.fromarray((255 * image).astype('uint8'))
    image_pil = image_pil.resize((256, 256))
    string_buf = StringIO.StringIO()
    image_pil.save(string_buf, format='png')
    data = string_buf.getvalue().encode('base64').replace('\n', '')
    return 'data:image/png;base64,' + data


def allowed_file(filename):
    return (
        '.' in filename and
        filename.rsplit('.', 1)[1] in ALLOWED_IMAGE_EXTENSIONS
    )


class ImagenetClassifier(object):
    default_args = {
        'deploy_file': (
            '{}/deploy.prototxt'.format(DATA_FOLDER)),
        'model_file': (
            '{}/resnet-50-cervix_iter_50000.caffemodel'.format(DATA_FOLDER)),
        'mean_file': (
            '{}/imagenet_mean.binaryproto'.format(DATA_FOLDER)),
        'labels_file': (
            '{}/synset_words.txt'.format(DATA_FOLDER)),
    }
    for key, val in default_args.iteritems():
        if not os.path.exists(val):
            raise Exception(
                "File for {} is missing. Should be at: {}".format(key, val))

    default_args['image_dim'] = 256
    default_args['raw_scale'] = 255.

    def __init__(self, deploy_file, model_file, mean_file,
                 raw_scale, labels_file, image_dim, gpu_mode):
        logging.info('Loading net and associated files...')
        if gpu_mode:
            caffe.set_mode_gpu()
        else:
            caffe.set_mode_cpu()

	mean_blob = caffe_pb2.BlobProto()
        with open(mean_file) as f:
            mean_blob.ParseFromString(f.read())
        mean_array = np.asarray(mean_blob.data, dtype=np.float32).reshape(
            (mean_blob.channels, mean_blob.height, mean_blob.width))

        # load the class labels from disk
        rows = open(labels_file).read().strip().split("\n")
        #self.classes = [r[r.find("|") + 1:].split(",")[0] for r in rows]
        self.classes = [r[r.find(" ") + 1:].split(",")[0] for r in rows]


        #Read model architecture and trained model's weights
        self.net = caffe.Net(deploy_file, model_file, caffe.TEST)


        #Define image transformers
        self.transformer = caffe.io.Transformer({'data': self.net.blobs['data'].data.shape})
        self.transformer.set_mean('data', mean_array)
        self.transformer.set_transpose('data', (2,0,1))


    def transform_img(img, img_width=IMAGE_WIDTH, img_height=IMAGE_HEIGHT):

        #Histogram Equalization
        img[:, :, 0] = cv2.equalizeHist(img[:, :, 0])
        img[:, :, 1] = cv2.equalizeHist(img[:, :, 1])
        img[:, :, 2] = cv2.equalizeHist(img[:, :, 2])

        #Image Resizing
        img = cv2.resize(img, (img_width, img_height), interpolation = cv2.INTER_CUBIC)

        return img

    def classify_image(self, image, sdkurl):
        try:
            logging.info('classify_image')
            #image = self.transform_img(image)
            #, img_width=IMAGE_WIDTH, img_height=IMAGE_HEIGHT)

            self.net.blobs['data'].data[...] = self.transformer.preprocess('data', image)

            starttime = time.time()
            out = self.net.forward()
            endtime = time.time()
            logging.info('classification took {:.5} seconds'.format(endtime - starttime))

            preds = out['prob']

            # sort the indexes of the probabilities in descending order (higher
            # probabilitiy first) and grab the top-5 predictions
            idxs = np.argsort(preds[0])[::-1][:5]

            # loop over the top-5 predictions and display them
            results = []
            for (i, idx) in enumerate(idxs):
                prob = preds[0][idx]
		if prob < 0.10:
			break
                classes = self.classes[idx].replace(" ", ",");
                logging.info("{} {} {:.5}".format(idx, labels[idx], prob))
		result = {}
		result["id"] = idx
		result["name"] = labels[idx]
		result["imgurl"] = sdkurl+"/images/"+urllib.quote(labels[idx])+".jpg"
		result["percent"] = "{:.3}".format(prob*100)
		results.append(result)
	    data = {"errcode":0, "count":len(results), "result":results}

            logging.info("Result:\n%s", json.dumps(data))

            return data

        except Exception as err:
            logging.info('Classification error: %s', err)
	    result = {"errcode":1, "errmsg":err}
            return data


def start_tornado(app, port=28070):
    http_server = tornado.httpserver.HTTPServer(
        tornado.wsgi.WSGIContainer(app))
    baseurl = "http://bob.geeekvr.com:"+str(port)
    http_server.listen(port)
    print("Tornado server starting on port {}".format(port))
    tornado.ioloop.IOLoop.instance().start()


def start_from_terminal(app):
    """
    Parse command line options and start the server.
    """
    parser = optparse.OptionParser()
    parser.add_option(
        '-d', '--debug',
        help="enable debug mode",
        action="store_true", default=False)
    parser.add_option(
        '-p', '--port',
        help="which port to serve content on",
        type='int', default=28070)
    parser.add_option(
        '-g', '--gpu',
        help="use gpu mode",
        action='store_true', default=False)

    opts, args = parser.parse_args()
    ImagenetClassifier.default_args.update({'gpu_mode': opts.gpu})

    # Initialize classifier + warm start by forward for allocation
    app.clf = ImagenetClassifier(**ImagenetClassifier.default_args)
    app.clf.net.forward()

    if opts.debug:
        app.run(debug=True, host='0.0.0.0', port=opts.port)
    else:
        start_tornado(app, opts.port)


if __name__ == '__main__':
    logging.getLogger().setLevel(logging.INFO)
    if not os.path.exists(UPLOAD_FOLDER):
        os.makedirs(UPLOAD_FOLDER)
    if not os.path.exists(THUMBNAIL_FOLDER):
        os.makedirs(THUMBNAIL_FOLDER)

    start_from_terminal(app)



安卓端部分代码:

设置端口号:

package com.example.birdrecognition.app;

import android.app.Application;
import android.content.res.Configuration;

public class MyApplication extends Application {
    private String sdkUrl = "http://bob.geeekvr.com:28008";

    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public void onTerminate() {
        super.onTerminate();
    }
    @Override
    public void onLowMemory() {
        super.onLowMemory();
    }
    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }

    public void setSdkUrl(String sdkUrl) { this.sdkUrl = sdkUrl; }

    public String getSdkUrl() { return sdkUrl; }

}



package com.example.birdrecognition.sdk;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

public class HttpConnect {

    public static String connect(String httpUrl, String message) throws IOException  {
        if (message==null) {
            return "";
        }
        Log.i("HttpConnect", "#Request:: "+message);
        String CONTENT_TYPE = "application/x-www-form-urlencoded";
        URL url = null;
        url = new URL(httpUrl);
        HttpURLConnection conn = null;
        conn = (HttpURLConnection) url.openConnection();
        conn.setReadTimeout(30000);
        conn.setConnectTimeout(30000);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Charset", "utf-8");
        conn.setRequestProperty("connection", "keep-alive");
        conn.setRequestProperty("Content-Type", CONTENT_TYPE);
        conn.setRequestProperty ("Content-Length",""+message.length());
        conn.connect();

        DataOutputStream dos = new DataOutputStream (conn.getOutputStream());
        dos.writeBytes(message);
        dos.flush ();
        dos.close ();

        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
        String s = "";
        StringBuffer sb = new StringBuffer("");
        while ((s = br.readLine()) != null ) {
            sb.append(s);
        }
        String ret = sb.toString();
        int res = conn.getResponseCode();
        conn.disconnect();
        dos = null;
        conn = null;
        url = null;
        Log.i("HttpConnect", "#Response:: "+ret);

        return ret;
    }

    @SuppressWarnings("rawtypes")
    public static String formUpload(String urlStr, Map<String, String> textMap,
                                    Map<String, String> fileMap, String contentType) {
        String res = "";
        HttpURLConnection conn = null;
        String BOUNDARY = "---------------------------123821742118716";
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("User-Agent","Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + BOUNDARY);
            OutputStream out = new DataOutputStream(conn.getOutputStream());

            if (textMap != null) {
                StringBuffer strBuf = new StringBuffer();
                Iterator iter = textMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""+ inputName + "\"\r\n\r\n");
                    strBuf.append(inputValue);
                }
                out.write(strBuf.toString().getBytes());
            }
            if (fileMap != null) {
                Iterator iter = fileMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    File file = new File(inputValue);
                    String filename = file.getName();
                    if (contentType == null || "".equals(contentType)) {
                        contentType = "application/octet-stream";
                    }
                    StringBuffer strBuf = new StringBuffer();
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""+ inputName + "\"; filename=\"" + filename+ "\"\r\n");
                    strBuf.append("Content-Type:" + contentType + "\r\n\r\n");
                    out.write(strBuf.toString().getBytes());
                    DataInputStream in = new DataInputStream(new FileInputStream(file));
                    int bytes = 0;
                    byte[] bufferOut = new byte[1024];
                    while ((bytes = in.read(bufferOut)) != -1) {
                        out.write(bufferOut, 0, bytes);
                    }
                    in.close();
                }
            }
            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();
            StringBuffer strBuf = new StringBuffer();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return res;
    }

    @SuppressWarnings("rawtypes")
    public static String formUploadCompressed(String urlStr, Map<String, String> textMap,
                                              Map<String, String> fileMap, String contentType) {
        String res = "";
        HttpURLConnection conn = null;
        String BOUNDARY = "---------------------------123821742118716";
        try {
            Log.i("HttpConnect", urlStr);
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("User-Agent","Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + BOUNDARY);
            OutputStream out = new DataOutputStream(conn.getOutputStream());
            if (textMap != null) {
                StringBuffer strBuf = new StringBuffer();
                Iterator iter = textMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""+ inputName + "\"\r\n\r\n");
                    strBuf.append(inputValue);
                }
                out.write(strBuf.toString().getBytes());
            }

            if (fileMap != null) {
                Iterator iter = fileMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    File file = new File(inputValue);
                    String filename = file.getName();
                    long filelength = file.length()/1024;
                    if (contentType == null || "".equals(contentType)) {
                        contentType = "application/octet-stream";
                    }
                    StringBuffer strBuf = new StringBuffer();
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""+ inputName + "\"; filename=\"" + filename+ "\"\r\n");
                    strBuf.append("Content-Type:" + contentType + "\r\n\r\n");
                    out.write(strBuf.toString().getBytes());
                    BitmapFactory.Options bo=new BitmapFactory.Options();
                    if (filelength > 2000) {
                        bo.inSampleSize = 4;
                    } else if (filelength > 1000) {
                        bo.inSampleSize = 2;
                    } else {
                        bo.inSampleSize = 1;
                    }
                    Bitmap image = BitmapFactory.decodeFile(inputValue,bo);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    image.compress(Bitmap.CompressFormat.JPEG, 100, baos);

                    int options = 90;
                    while (baos.toByteArray().length / 1024 > 200 && options > 10 ) {
                        Log.i("HttpConnect", "options: "+options);
                        baos.reset();
                        image.compress(Bitmap.CompressFormat.JPEG, options, baos);
                        options -= 10;
                    }

                    InputStream is = new ByteArrayInputStream(baos.toByteArray());
                    byte[] bufferOut = new byte[1024];
                    int len = 0;
                    while ((len=is.read(bufferOut)) != -1){
                        out.write(bufferOut, 0, len);
                    }
                    is.close();
                }
            }
            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();

            StringBuffer strBuf = new StringBuffer();
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return res;
    }

    public static String get(String httpUrl) throws IOException  {
        String CONTENT_TYPE = "application/x-www-form-urlencoded";
        URL url = null;
        url = new URL(httpUrl);
        HttpURLConnection conn = null;
        conn = (HttpURLConnection) url.openConnection();
        conn.setReadTimeout(30000);
        conn.setConnectTimeout(30000);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Charset", "utf-8");
        conn.setRequestProperty("connection", "keep-alive");
        conn.setRequestProperty("Content-Type", CONTENT_TYPE);
        conn.connect();

        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
        String s = "";
        StringBuffer sb = new StringBuffer("");
        while ((s = br.readLine()) != null ) {
            sb.append(s);
        }
        String ret = sb.toString();

        conn.disconnect();
        conn = null;
        url = null;

        return ret;
    }
}


package com.example.birdrecognition.sdk;

public class ImageUploadRequest extends PublicRequest implements IRequest {
    private String file;
    private int source;
    private String userToken;


    @Override
    public String getUrl() {
        return sdkUrl+"/classify_upload?access_token="+accessToken;
    }

    @Override
    public String getRequestJson() {
        return null;
    }

    public String getFile() {
        return file;
    }

    public void setFile(String file) {
        this.file = file;
    }

    public String getUserToken() { return userToken; }

    public void setUserToken(String user_token) {
        this.userToken = userToken;
    }

    public void setSource(int source) { this.source = source; }

    public int getSource() { return source; }


}


package com.example.birdrecognition.sdk;

import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONObject;

public class ImageUploadResponse extends PublicResponse implements IResponse {
    private int count;
    private ArrayList<String> id;
    private ArrayList<String> name;
    private ArrayList<String> percent;

    @Override
    public void parseJSON(String jsonStr) {
        jsonResponse = jsonStr;
        if (jsonStr == null || jsonStr.length() == 0) {
            errcode = 998;
            errmsg = "返回JSON为空";
        }
        try {
            JSONObject obj = new JSONObject(jsonStr);

            errcode = getInt(obj,"errcode",997);
            errmsg = get(obj,"errmsg","JSON解析错误");
            id = new ArrayList<String>();
            name = new ArrayList<String>();
            percent = new ArrayList<String>();

            if (errcode == 0) {
                count = getInt(obj,"count",0);
                if (count > 0) {
                    JSONArray resultArray = obj.getJSONArray("result");
                    int len = resultArray.length();
                    for(int i=0;i<len;i++) {
                        id.add(get(resultArray.getJSONObject(i),"id",""));
                        name.add(get(resultArray.getJSONObject(i),"name",""));
                        percent.add(get(resultArray.getJSONObject(i),"percent",""));
                    }
                }
            }

        } catch(Exception e) {
            errcode = 997;
            errmsg = "未连接服务器";
        }
    }

    public int getCount() {
        return count;
    }

    public ArrayList<String> getId() {
        return id;
    }

    public ArrayList<String> getName() {
        return name;
    }

    public ArrayList<String> getPercent() {
        return percent;
    }
}

上面的代码中,服务端和安卓端的ip地址+端口号,其实每次调试时设置的都是相同的,上面忘记改了

安卓连接自己服务器,要开一下自己电脑的防火墙...不然不能访问..

你这云服务器加了https没?新的安全策略不允许http访问