前言
- 用yolov8训练了个模型,想对接到易语言,发现大漠插件只支持yolov5模型,就放弃使用插件对接了。
- 于是用python的fastapi把yolov8的模型调用写成了接口,这时就用到了http协议,需要post上传屏幕截图进行识别
- 直接使用python进行post上传的代码大致格式如下
import requests if __name__ == '__main__': with open('C:\Users\daowuya\Desktop\1.jpg', 'rb') as fp: req = requests.post('http://*.*.*.*:1234/detect', files={'file_list': ('1.jpg', fp.read())}) req.encoding = 'utf-8' print(req.text)
- 而对于易语言,可没法用这么简单的写法。
易语言调用POST上传图片
首先看下命令 "网络_访问_对象" 的参数
子程序名:网页_访问_对象
使用WinHttp的对象方式访问网页
返回值类型:字节集
参数<1>的名称为“网址”,类型为“文本型”。注明:完整的网页地址,必须包含http://或者https://。
参数<2>的名称为“访问方式”,类型为“整数型”,允许接收空参数数据。注明:0=GET 1=POST 2=HEAD 3=PUT 4=OPTIONS 5=DELETE 6=TRACE 7=CONNECT。
参数<3>的名称为“提交信息”,类型为“文本型”,允许接收空参数数据。注明:"POST"专用 自动UTF8编码。
参数<4>的名称为“提交Cookies”,类型为“文本型”,接收参数数据时采用参考传递方式,允许接收空参数数据。注明:设置提交时的cookie。
参数<5>的名称为“返回Cookies”,类型为“文本型”,接收参数数据时采用参考传递方式,允许接收空参数数据。注明:返回的Cookie。
参数<6>的名称为“附加协议头”,类型为“文本型”,允许接收空参数数据。注明:一行一个请用换行符隔开。
参数<7>的名称为“返回协议头”,类型为“文本型”,接收参数数据时采用参考传递方式,允许接收空参数数据。注明:返回的协议头。
参数<8>的名称为“返回状态代码”,类型为“整数型”,接收参数数据时采用参考传递方式,允许接收空参数数据。注明:网页返回的状态代码,例如:200;302;404等。
参数<9>的名称为“禁止重定向”,类型为“逻辑型”,允许接收空参数数据。注明:默认不禁止网页重定向。
参数<10>的名称为“字节集提交”,类型为“字节集”,允许接收空参数数据。注明:提交字节集数据。
...省略剩余用不到的参数
在执行非上传文件的post时,请求体一般设置在参数<3>。
但是,涉及到了上传文件,那么肯定就是以字节集的形式了,参数<3>已经指定类型为“文本型”了,所以就不能在参数<3>设置了。
看到字节集,自然而然就关注到参数<10>:“字节集提交”
当然,事情没这么简单。直接进行post然后用易语言的“打开文件"的命令进行上传,发现还是不行。
那么,该如何切入?
于是,我就想到了抓包,然后按格式去模拟浏览器的请求(笑死,还要抓包自己写的接口)
为了明了,我将请求整理成了报文的形式
POST http://*.*.*.*:1234/detect HTTP/1.1
Accept:application/json
Accept-Language:zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryLVed6HpVQPCdDf1Z
Host:*.*.*.*:1234
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61
下面是“已解码视图”的表单数据
file_list: (二进制)
modelName: yolov5s
img_size: 640
conf: 0.5
classes: all
download_image: false
下面是“源”的表单数据
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="file_list"; filename="1.jpg"
Content-Type: image/jpeg
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="modelName"
yolov5s
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="img_size"
640
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="conf"
0.5
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="classes"
all
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="download_image"
false
------WebKitFormBoundaryLVed6HpVQPCdDf1Z--
综上,发送的请求就需要按照“源”的表单数据进行模拟
那么,正文开始:
新建常量,将“源”内容放进去,当然上面的源是不全的,还需要加入上传的文件,上面的源中仅仅是文件的名字而已,那么具体该怎么做呢?添加占位符,后面将源转成字节集后,再用字节集替换命令将占位符替换成上传的文件的字节集就好了!当然如果源里面的其他值(例img_size等)需要频繁修改的话,也可以添加占位符进行替换。下面是示例(“上传的文件路径”即为占位符)
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="file_list"; filename="1.jpg"
Content-Type: image/jpeg
上传的文件路径
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="modelName"
yolov5s
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="img_size"
640
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="conf"
0.5
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="classes"
all
------WebKitFormBoundaryLVed6HpVQPCdDf1Z
Content-Disposition: form-data; name="download_image"
false
------WebKitFormBoundaryLVed6HpVQPCdDf1Z--
那么具体实现就是:通过 “编码_Ansi到Utf8” 将定义的常量转化为字节集,再使用“子字节集替换”将占位符替换成打开的图片的字节集,即可,具体代码如下:
.版本 2
.支持库 spec
.子程序 获取yolo检测结果, 文本型
.局部变量 网址, 文本型
.局部变量 方式, 整数型
.局部变量 结果, 文本型
.局部变量 提交数据, 文本型
.局部变量 协议头, 文本型
.局部变量 数据包, 字节集
网址 = “http://*.*.*.*:1234/detect”
方式 = 1
协议头 = “Accept: application/json” + #换行符 + “Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6” + #换行符 + “Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryLVed6HpVQPCdDf1Z” + #换行符 + “User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61”
数据包 = 编码_Ansi到Utf8 (#常量)
数据包 = 子字节集替换 (数据包, 编码_Ansi到Utf8 (“文件路径”), 读入文件 (“C:\Users\daowuya\Desktop\1.jpg”), , )
结果 = 到文本 (网页_访问_对象 (网址, 方式, , , , 协议头, , , , 数据包, ))
调试输出 (结果)
返回 (结果)
' yolov8接口识别结果
' [[{\"class\": 2, \"class_name\": \"sun\", \"bbox\": [618, 225, 742, 322], \"confidence\": 0.9670454859733582}, {\"class\": 1, \"class_name\": \"cao\", \"bbox\": [401, 209, 534, 307], \"confidence\": 0.9659115672111511}, {\"class\": 2, \"class_name\": \"sun\", \"bbox\": [452, 333, 574, 432], \"confidence\": 0.956778347492218}, {\"class\": 0, \"class_name\": \"liu\", \"bbox\": [553, 424, 696, 520], \"confidence\": 0.9409418702125549}, {\"class\": 1, \"class_name\": \"cao\", \"bbox\": [389, 449, 540, 545], \"confidence\": 0.9399887323379517}, {\"class\": 0, \"class_name\": \"liu\", \"bbox\": [236, 377, 379, 475], \"confidence\": 0.9376011490821838}, {\"class\": 0, \"class_name\": \"liu\", \"bbox\": [704, 348, 833, 446], \"confidence\": 0.9322284460067749}, {\"class\": 0, \"class_name\": \"liu\", \"bbox\": [188, 264, 354, 362], \"confidence\": 0.9117769598960876}]]