云里听内网发送代码 --镇江
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

463 lines
17 KiB

9 months ago
import datetime
import math
import os
import signal
import sys
import threading
import re
import uuid
import tempfile
import pyexiv2
import numpy as np
import requests
from PIL import Image
from numpy import arctan
import cv2
from math import tan, cos, sin
import oss2
import paho.mqtt.client as mqtt
import concurrent.futures
import json
# 客户端id
client_id='python_gengbao'
# 订阅主题
longandlat_mqtt ='task/image/gps/custon'
# 订阅主题
appTwo ='task/image/disobey/handle'
# 订阅主题
weijian ='task/image/pixel/custon'
# 发布通知主题
pushNoticeTopic ='task/image/disobey/confirm'
access_key = "LTAI5tMDFvYZRvrJfK7HeuEm"
secret_key = "kP7ueRlhLbM9mvkaLtHfcje3GxgawH"
endpoint = "oss-cn-hangzhou.aliyuncs.com"
bucket_name = "yq-dajiang"
auths = oss2.Auth(access_key, secret_key)
bucket = oss2.Bucket(auths, endpoint, bucket_name)
# 根据像素坐标生成图片和经纬度,放入集合中,返回到前端
client = mqtt.Client(client_id=client_id)
#截图
def crop_image(input_image,center_x,center_y):
print(center_x,center_y)
#固定截图尺寸 1000*1000
l_x = 0
l_y=0
r_x=1000
r_y=1000
if center_x>500:
l_x=center_x-500
r_x=center_x+500
if r_x>=4000:
r_x=4000
l_x=3000
if center_y>500:
l_y=center_y-500
r_y=center_y+500
if r_y>=3000:
r_y=3000
l_y=2000
print((l_x,l_y),(r_x,r_y))
# 截取指定区域图像
cropped_image = input_image[l_y:r_y, l_x:r_x]
return np.array(cropped_image)
#计算两个经纬度之间的距离,用于计算长宽
def dimension(jingduA, weiduA,jingduB, weiduB):
R = 6371.393
Pi = math.pi
a = (math.sin(math.radians(weiduA / 2 - weiduB / 2))) ** 2
b = math.cos(weiduA * Pi / 180) * math.cos(weiduB * Pi / 180) * (
math.sin((jingduA / 2 - jingduB / 2) * Pi / 180)) ** 2
dimension = 2 * R * math.asin((a + b) ** 0.5) * 1000
return dimension
def sum(focalLength,x,altitude):
width=4000
#靶面宽
ba=6.2
#实际长度
wr=(x*altitude*ba)/(focalLength*width)
return wr
def longandlat(pixel_x,pixel_y,imageMap):
# 焦距
focalLength =float(imageMap["focalLength"])
# 经纬度
longitude_str=imageMap["longitude"]
latitude_str = imageMap["latitude"]
# 使用正则表达式提取度、分和秒的数值
pattern = r"(\d+)° (\d+)' ([\d.]+)\""
longitude_match = re.match(pattern, longitude_str)
latitude_match = re.match(pattern, latitude_str)
print(longitude_match)
print(type(longitude_match))
# 度
lg_du =int(longitude_match.group(1))
# 分
lg_fen =int(longitude_match.group(2))
# 秒
lg_seconds = float(longitude_match.group(3))
# 度
la_du = int(latitude_match.group(1))
# 分
la_fen = int(latitude_match.group(2))
# 秒
la_seconds =float(latitude_match.group(3))
# 海拔
altitude = float(imageMap["altitude"])
# 图片宽高
width =float(imageMap["width"])
height =float(imageMap["height"])
# 中点坐标
x, y = width // 2, height // 2
# 通过勾股定理可以计算出 1/2.3 英寸对角线的长度大约为 4.54 毫米。
D = 2 * tan(arctan(9.826 / 2 / focalLength) / 2) * altitude
# 因此,每个像素所代表的实际距离为(米):
# p =(9.826*altitude)/(width*focalLength)
p = D / width
# 经度每秒代表的距离 m
# 纬度每秒代表的距离 m
lat_p = 23.6
long_p = 30.9
pie=float(imageMap["xmpProperties"])
if pie < 0:
pie = -180 + abs(pie)
else:
pie = 180 - pie
# z转换已中心点为原点的坐标体系
px = (pixel_x - x)
py = (y - pixel_y)
a = math.radians(pie)
# 坐标体系旋转后所得到的坐标
c_a_x = cos(a) * px - sin(a) * py
c_a_y = sin(a) * px + cos(a) * py
ys = c_a_y * p / lat_p
xs = c_a_x * p / long_p
la_seconds += ys
lg_seconds += xs
longitude_x = lg_du + lg_fen / 60.0 + lg_seconds / 3600.0
latitude_y = la_du + la_fen / 60.0 + la_seconds / 3600.0
return longitude_x ,latitude_y,focalLength,altitude
def upload_image_to_oss(imgeName,data):
# imgeName 文件名 列:python/img.jpg
bucket.put_object(imgeName, data)
# 将对象权限设置为公共读,以便通过URL访问上传的图像
bucket.put_object_acl(imgeName, oss2.OBJECT_ACL_PUBLIC_READ)
# 获取对象URL
url = bucket.sign_url("GET", imgeName,3600) # URL有效期为1小时
return url.split('?')[0]
# 连接回调函数
def on_connect(client, userdata, flags, rc):
"""一旦连接成功, 回调此方法"""
rc_status = ["连接成功", "协议版本错误", "无效的客户端标识", "服务器无法使用", "用户名或密码错误", "无授权"]
print("connect:", rc_status[rc])
topics = [str(weijian), str(longandlat_mqtt), str(appTwo)]
# 要订阅的主题列表
for topic in topics:
# 订阅主题
print("订阅主题:", topic)
client.subscribe(topic)
def compute(re):
if "sourceImgUrl" in re and "pixelCoordinate" in re:
sourceImgUrl = re["sourceImgUrl"]
mateSourceImgUrl = re["mateSourceImgUrl"]
pixelCoordinate = re["pixelCoordinate"]
imageMap = re["imageMap"]
maplist=[]
# 如果image1和image2都不为空,执行相关操作
# 指向算法比对,获取图片z
if pixelCoordinate:
coordinateList = json.loads(pixelCoordinate)
# 指向算法比对,获取图片
if len(coordinateList) != 0:
# 从URL加载图像
resp = requests.get(sourceImgUrl)
# 创建临时文件
# 创建临时文件
temp_file = tempfile.NamedTemporaryFile(delete=False)
temp_file.write(resp.content)
temp_file.close()
# 前端缩放了,比例是:scale=4
for item in coordinateList:
lef_x = item["lef_x"]
lef_y = item["lef_y"]
right_x = item["right_x"]
right_y = item["right_y"]
# 将比例还原
scale = 4
lef_x = int(lef_x * scale)
lef_y = int(lef_y * scale)
right_x = int(right_x * scale)
right_y = int(right_y * scale)
x=right_x-lef_x
y=right_y-lef_y
# 中心坐标
# 计算矩形框的中心点坐标
center_x = int((lef_x + right_x) / 2)
center_y = int((lef_y + right_y) / 2)
# 经纬度转换
long, lat ,focalLength,altitude= longandlat(center_x, center_y, imageMap)
img_array = np.frombuffer(resp.content, np.uint8)
# 将矩形框绘制到图片上
img_copy = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
# 在图像上绘制矩形框
cv2.rectangle(img_copy, (lef_x,lef_y), (right_x,right_y), (0, 255, 255), 10)
# OpenCV图像对象转换为字节流格式。
_, buffer = cv2.imencode('.jpg', img_copy)
img_bytes = buffer.tobytes()
# 文件名称
unique_id = str(uuid.uuid4())
imgName = 'python/' + unique_id + "违建图.jpg"
# 将图片上传到阿里云OSS
url = upload_image_to_oss(imgName, img_bytes)
# 获取长
w = sum(focalLength,x,altitude)
# 获取宽
h = sum(focalLength,y,altitude)
# 计算矩形面积并保留两位小数
area = round(w * h, 2)
#截图 对比图放大
cropped_image1=crop_image(img_copy, center_x,center_y)
# OpenCV图像对象转换为字节流格式。
_, buffer1 = cv2.imencode('.jpg',cropped_image1)
img_bytes1 = buffer1.tobytes()
# 文件名称
unique_id1 = str(uuid.uuid4())
imgNameOne = 'python/' + unique_id1 + "对比图违建放大图.jpg"
# 将图片上传到阿里云OSS
maxImages = upload_image_to_oss(imgNameOne, img_bytes1)
# 从URL加载图像
resp1 = requests.get(mateSourceImgUrl)
# 创建临时文件
temp_file1 = tempfile.NamedTemporaryFile(delete=False)
temp_file1.write(resp1.content)
temp_file1.close()
# 模板图画框
img_array2 = np.frombuffer(resp1.content, np.uint8)
# 将矩形框绘制到图片上
img_copy2 = cv2.imdecode(img_array2, cv2.IMREAD_COLOR)
# 在图像上绘制矩形框
cv2.rectangle(img_copy2, (lef_x, lef_y), (right_x, right_y), (255, 255, 0), 10)
# OpenCV图像对象转换为字节流格式。
_, buffer2 = cv2.imencode('.jpg', img_copy2)
img_bytes2 = buffer2.tobytes()
# 文件名称
unique_id3 = str(uuid.uuid4())
imgName3 = 'python/' + unique_id3 + "违建图.jpg"
# 将图片上传到阿里云OSS
url3 = upload_image_to_oss(imgName3, img_bytes2)
cropped_image2 = crop_image(img_copy2,center_x,center_y) # OpenCV图像对象转换为字节流格式。
_, buffer1 = cv2.imencode('.jpg',cropped_image2)
img_bytes2 = buffer1.tobytes()
# 文件名称
unique_id2 = str(uuid.uuid4())
imgNameTwo = 'python/' + unique_id2 + "放大模板图.jpg"
# 将图片上传到阿里云OSS
maxMateSourceImgUrl = upload_image_to_oss(imgNameTwo, img_bytes2)
id = re["id"]
taskId = re["taskId"]
map = {"lng": long, "lat": lat, "url": url, "taskImageId": id, "taskId": taskId, "images": url,
"handleType": 1,"areaL":w,"areaW":h,"area":area,"maxMateSourceImgUrl":maxMateSourceImgUrl,
"maxImages":maxImages,"mateSourceImgUrl":url3}
maplist.append(map)
return maplist
# 根据像素坐标生成图片和经纬度,放入集合中,返回到前端
def result(re,imgeurl,coordinateList):
if len(coordinateList)!=0:
print("读取")
# 从URL加载图像
imgeurl=str(imgeurl).replace("https", "http")
resp = requests.get(imgeurl,stream=True)
# 创建临时文件
with tempfile.NamedTemporaryFile(delete=False) as temp_file:
for chunk in resp.iter_content(chunk_size=1024):
temp_file.write(chunk)
print("创建")
# 创建pyexiv2.Image对象
# 从临时文件读取图像数据
image = cv2.imread(temp_file.name)
if image is not None:
# 文件名称
unique_id = str(uuid.uuid4())
print("生成")
#前端缩放了,比例是:scale=4
for item in coordinateList:
print(type(item))
lef_x=item["lef_x"]
lef_y=item["lef_y"]
right_x = item["right_x"]
right_y = item["right_y"]
#将比例还原
scale=4
lef_x=lef_x*scale
lef_y=lef_y*scale
right_x=right_x*scale
right_y=right_y*scale
# # 中心坐标
# # 计算矩形框的中心点坐标
# center_x = int(lef_x+right_x / 2)
# center_y = int(lef_y+right_y / 2)
# # # 经纬度转换
# # long,lat=longandlat(image,center_x,center_y)
# # 将矩形框绘制到图片上
# nparr = np.frombuffer(resp.content, np.uint8)
# img_copy = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
# 在图像上绘制矩形框
cv2.rectangle(image, (int(lef_x),int(lef_y)), (int(right_x),int(right_y)), (0,0,255), 10)
# OpenCV图像对象转换为字节流格式。
_, buffer = cv2.imencode('.jpg', image)
img_bytes = buffer.tobytes()
imgName = 'python/' + unique_id + "违建图.jpg"
print("上传")
# 将图片上传到阿里云OSS
url = upload_image_to_oss(imgName, img_bytes)
id = re["id"]
taskId = re["taskId"]
map = {"id": id, "taskId": taskId,"discernImgUrl": url}
os.remove(temp_file.name)
return map
def messageData(msg):
topic = msg.topic
print("处理消息,时间:" + str(datetime.datetime.now()))
data = json.loads(msg.payload.decode())
# 获取图片路径、图片名称和MQTT消息的时间戳
if data:
if topic==appTwo:
print("通知")
if "id" in data:
print("数据情况",data)
id=data["id"]
notice = {"id":id }
on_publish(pushNoticeTopic, json.dumps(notice), 0)
if topic==weijian:
print("画违建矩形框")
if "sourceImgUrl" in data and "pixelCoordinate" in data:
image = data["sourceImgUrl"]
pixelCoordinate = data["pixelCoordinate"]
# 指向算法比对,获取图片
coordinateList = json.loads(pixelCoordinate)
print(type(coordinateList))
map = result(data, image, coordinateList)
if map is None:
print("生成图片出错,为null")
else:
url = "http://106.13.50.125:9006/ploughe-boot/wayline/waylineTaskImage/leakEdit"
# url = "http://192.168.1.20:9005/ploughe-boot/wayline/waylineTaskImage/leakEdit"
# 调取接口
response = requests.post(url, json=map)
message = response.text
print("接口返回值:", message)
print("结束时间:" + str(datetime.datetime.now()))
elif topic==longandlat_mqtt:
print("提交违建,生产预警")
# 创建线程池
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
if data and "waylineTaskImages" in data:
waylineImgList = data["waylineTaskImages"]
# 提交任务给线程池
futurelist = [executor.submit(compute, re) for re in waylineImgList]
# 等待所有任务完成
concurrent.futures.wait(futurelist)
# 获取每个任务的处理结果
final_results = [item for sublist in
[future.result() for future in futurelist if future.result() is not None] for item
in
sublist]
print("返回的结果", final_results)
print("返回的结果数量", len(final_results))
if len(final_results) != 0:
data['waylineTaskHandles'] = final_results
print("提交数据:", data)
url = "http://106.13.50.125:9006/ploughe-boot/wayline/waylineTaskWhee/leakEdit"
# url = "http://192.168.1.20:9005/ploughe-boot/wayline/waylineTaskWhee/leakEdit"
# 调取接口
# 将list作为JSON数据
# 发送POST请求,并将data作为请求体
response = requests.post(url, json=data, headers={'Content-Type': 'application/json'})
# 获取响应结果
body = response.json()
print("接口返回值:", body)
print("结束时间:" + str(datetime.datetime.now()))
# 关闭线程池
executor.shutdown()
def on_message(client, userdata, msg):
# """一旦订阅到消息, 回调此方法"""
print("主题:" + msg.topic + " 消息:" + msg.payload.decode('utf-8')) # 客户端返回的消息,使用gb2312编码中文不会报错
# 多线程执行
threading.Thread(target=messageData, args=((msg,))).start()
def signal_handler(signal, frame):
print('接收到键盘中断信号,程序将退出')
sys.exit(0)
def on_publish(topic, payload, qos):
re=client.publish(topic, payload, qos)
print("结果:"+str(re)+"时间:"+str(datetime.datetime.now()))
def run():
# 创建客户端对象
client.username_pw_set("adminRQ", "yongqiang666")
# 设置连接回调函数
client.on_connect = on_connect
# 设置接收消息回调函数
client.on_message = on_message
# 连接到MQTT代理
client.connect("106.13.50.125", 1883, 60)
# 注册信号处理程序
signal.signal(signal.SIGINT, signal_handler)
# 保持连接并接收消息
client.loop_forever()
if __name__ == '__main__':
run()