作业过程中动态执行视频监控

This commit is contained in:
曹前明 2022-08-12 17:17:10 +08:00
parent 811f96fe83
commit 1806eb80bb
25 changed files with 451 additions and 65 deletions

View File

@ -143,6 +143,11 @@ class TestViewSet(CustomGenericViewSet):
ret = {}
task = show.delay(*vdata.get('args', []), **vdata.get('kwargs', {}))
ret['task_id'] = task.task_id
# from celery.app.control import Control
# from server.celery import app
# celery_control = Control(app=app)
# # 关闭作业监控任务
# res = celery_control.revoke(task.task_id, terminate=True)
return Response(ret)
@action(methods=['post'], detail=False, serializer_class=Serializer)

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.12 on 2022-08-11 06:03
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('opm', '0002_initial'),
('ecm', '0013_auto_20220810_1512'),
]
operations = [
migrations.AddField(
model_name='event',
name='operation',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='opm.operation', verbose_name='关联作业'),
),
migrations.AddField(
model_name='eventcate',
name='opl_cates',
field=models.ManyToManyField(to='opm.OplCate', verbose_name='关联许可证'),
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 3.2.12 on 2022-08-12 09:15
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('opm', '0002_initial'),
('ecm', '0014_auto_20220811_1403'),
]
operations = [
migrations.RemoveField(
model_name='event',
name='operation',
),
migrations.AddField(
model_name='event',
name='opl',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='opm.opl', verbose_name='关联许可证'),
),
]

View File

@ -1,6 +1,7 @@
from django.db import models
from apps.am.models import Area
from apps.hrm.models import Employee
from apps.opm.models import Opl, OplCate
from apps.utils.models import BaseModel, CommonADModel, CommonAModel, CommonBModel
from apps.system.models import Post, User
from apps.third.models import TDevice
@ -28,6 +29,7 @@ class EventCate(CommonAModel):
default=Area.AREA_1)
hanle_minute = models.PositiveSmallIntegerField('处理时间', default=0, help_text='超过处理时间事件状态变为超时未处理,0代表未配置')
same_allow_minute = models.PositiveSmallIntegerField('允许时间', default=0, help_text='同一对象同事件多长时间内不再触发, 0代表一直触发')
opl_cates = models.ManyToManyField(OplCate, verbose_name='关联许可证')
def __str__(self):
return self.name
@ -83,6 +85,7 @@ class Event(CommonBModel):
area = models.ForeignKey(Area, verbose_name='发生区域', on_delete=models.CASCADE, null=True, blank=True)
vchannel = models.ForeignKey(TDevice, verbose_name='抓拍设备', on_delete=models.CASCADE, null=True, blank=True)
location = models.JSONField('事件点位坐标', default=dict, null=False, blank=True)
opl = models.ForeignKey(Opl, verbose_name='关联许可证', on_delete=models.CASCADE, null=True, blank=True)
obj_cate = models.CharField('发生对象', max_length=20, help_text='people(人员)/...')
employee = models.ForeignKey(Employee, verbose_name='当事人',
on_delete=models.CASCADE, null=True, blank=True)

View File

@ -78,6 +78,7 @@ class EventSerializer(serializers.ModelSerializer):
area_ = AreaSerializer(source='area', read_only=True)
cates_ = EventCateSimpleSerializer(source='cates', read_only=True, many=True)
employee_ = EmployeeSerializer(source='employee', read_only=True)
vchannel_ = TDeviceSimpleSerializer(source='vchannel', read_only=True)
handle_user_name = serializers.CharField(source='handle_user.name', read_only=True)
face_img = MyFilePathField()
global_img = MyFilePathField()

View File

@ -77,7 +77,7 @@ def algo_handle(codes: list, data: dict):
return ['helmet']
def notify_event(event: Event):
def notify_event(event: Event, voice_msg=''):
"""事件后续处理:
Args:
@ -87,7 +87,7 @@ def notify_event(event: Event):
ep = event.employee
obj_cate = event.obj_cate
params = {'area': event.area.name, 'employee': '', 'event': ''}
if obj_cate == 'people' and ep:
if ep:
ep_name = ep.name
ep_type = '员工'
if ep.type == 'rempoyee':
@ -97,11 +97,14 @@ def notify_event(event: Event):
params['employee'] = ep_type + ep_name
elif obj_cate == 'people':
params['employee'] = '未知人员'
elif obj_cate == 'area':
params['employee'] = '区域'
for i in event.cates.all():
params['event'] = params['event'] + i.name + ','
event.voice_msg = '位于{}{},{}请及时处理'.format(params['area'], params['employee'], params['event'])
if params['employee']:
event.voice_msg = '位于{}{},{}请及时处理'.format(params['area'], params['employee'], params['event'])
else:
event.voice_msg = '{}下,发生{}请及时处理'.format(params['area'], params['event'])
if voice_msg:
event.voice_msg = voice_msg
event.save()
# 喇叭播放
Thread(target=save_voice_and_speak, args=(event,), daemon=True).start()
@ -119,18 +122,19 @@ def save_voice_and_speak(event: Event):
v_p, v_num = main_cate.voice_person, main_cate.voice_num
_, event.voice, _ = generate_voice(event.voice_msg, v_p)
event.save()
if event.area: # 如果事件存在发生区域
sps = list(TDevice.objects.filter(area=event.area, type=TDevice.DEVICE_SPEAKER).values_list('code', flat=True))
if len(sps) == 0: # 如果当前区域没有喇叭就找覆盖区的喇叭
sps = list(TDevice.objects.filter(areas=event.area,
type=TDevice.DEVICE_SPEAKER).values_list('code', flat=True))
# 查找固定喇叭
for m in event.cates.all():
for n in m.speakers.all():
if n.code not in sps:
sps.append(n.code)
if sps:
spClient.speak(event.voice, sps, v_num)
if main_cate.speaker_on:
if event.area: # 如果事件存在发生区域
sps = list(TDevice.objects.filter(area=event.area, type=TDevice.DEVICE_SPEAKER).values_list('code', flat=True))
if len(sps) == 0: # 如果当前区域没有喇叭就找覆盖区的喇叭
sps = list(TDevice.objects.filter(areas=event.area,
type=TDevice.DEVICE_SPEAKER).values_list('code', flat=True))
# 查找固定喇叭
for m in event.cates.all():
for n in m.speakers.all():
if n.code not in sps:
sps.append(n.code)
if sps:
spClient.speak(event.voice, sps, v_num)
def create_remind(event: Event, params: dict):
@ -221,10 +225,10 @@ def dispatch_dahua_event(data: dict):
event = None
if alarm_type in [1001003, 1001000] and vchannel: # 内部人员/或陌生人报警
# 查看加载的算法
algo_codes = list(AlgoChannel.objects.filter(vchannel=vchannel).exclude(
algo_codes = list(AlgoChannel.objects.filter(vchannel=vchannel, algo__self_algo=True).exclude(
algo__code=None).order_by('algo__priority', 'algo__create_time').values_list('algo__code', flat=True))
area = vchannel.area # 视频所在区域
if algo_codes and area: # 如果加载了算法且视频通道绑定区域才继续
if algo_codes: # 如果加载了算法才继续
face_img_o = dhClient.get_full_pic(data['info']['alarmPicture'])
global_img_o = dhClient.get_full_pic(data['info']['extend']['globalScenePicUrl'])
obj_cate = 'people'
@ -250,6 +254,59 @@ def dispatch_dahua_event(data: dict):
'cate': i,
'event': event
})
elif alarm_type in [302, 303] and vchannel:
ec = EventCate.objects.filter(code=str(alarm_type)).first()
event = None
global_img_o = dhClient.get_full_pic(data['info']['alarmPicture'])
happen_time = timestamp_to_time(int(data['info']['alarmDate']))
if ec: # 先查看是否有定义该事件种类
event = Event()
event.global_img = save_dahua_pic(global_img_o)
event.area = vchannel.area
event.obj_cate = 'other'
event.vchannel = vchannel
event.happen_time = happen_time
event.save()
Eventdo.objects.get_or_create(cate=ec, event=event, defaults={
'cate': ec,
'event': event
})
# 查看加载的算法
algo_codes = list(AlgoChannel.objects.filter(vchannel=vchannel, algo__self_algo=True).exclude(
algo__code=None).order_by('algo__priority', 'algo__create_time').values_list('algo__code', flat=True))
if algo_codes:
ec_codes = algo_handle(algo_codes, data={}) # 算法处理
if ec_codes:
# 获取本次所有发生事件种类
ecs = EventCate.objects.filter(code__in=ec_codes)
obj_cate = 'other'
ep = None
if 'helmet' in ec_codes:
# 如果存在安全帽事件
# 尝试以图搜图找到当事人
res = dhClient.face_search(path=global_img_o)
if res and res[0]:
ep = Employee.objects.filter(id_number=res[0]['identity']).first()
if ep:
obj_cate = 'people'
if event is None: # 如果未创建事件
event = Event()
event.global_img = save_dahua_pic(global_img_o)
event.area = vchannel.area
event.obj_cate = obj_cate
event.employee = ep
event.vchannel = vchannel
event.happen_time = happen_time
event.save()
else:
event.obj_cate = obj_cate
event.employee = ep
event.save()
for i in ecs:
Eventdo.objects.get_or_create(cate=i, event=event, defaults={
'cate': i,
'event': event
})
if event:
notify_event(event)
@ -450,7 +507,7 @@ def blt_online(data):
blts = TDevice.objects.filter(code=data['userId']).first()
if blts.employee:
ep = blts.employee
if ep.type == 'employee' and ep.is_at_work is False:
if ep.type == 'employee' and ep.is_atwork is False:
# 上班打卡
now = timezone.now()
cr_10 = ClockRecord.objects.filter(type=10, employee=ep, create_time__year=now.year,
@ -468,7 +525,8 @@ def blt_online(data):
cr_10.trigger = 'location'
cr_10.detail = data
cr_10.save()
ep.is_at_work = True
ep.is_atwork = True
ep.last_check_time = now
ep.save()
@ -477,7 +535,7 @@ def blt_offline(data):
# 定位离线
if blts.employee:
ep = blts.employee
if ep.type == 'employee' and ep.is_at_work:
if ep.type == 'employee' and ep.is_atwork:
# 下班打卡
now = timezone.now()
cr_20 = ClockRecord.objects.filter(type=20, employee=ep, create_time__year=now.year,
@ -495,7 +553,8 @@ def blt_offline(data):
cr_20.trigger = 'location'
cr_20.detail = data
cr_20.save()
ep.is_at_work = False
ep.is_atwork = False
ep.last_check_time = now
ep.save()

View File

@ -6,11 +6,16 @@ from celery import shared_task
from apps.am.models import Area
from apps.ecm.models import EventCate, Eventdo
from apps.ecm.service import notify_event
from apps.ecm.service import algo_handle, notify_event, save_dahua_pic
from apps.hrm.models import Employee
from apps.opm.models import Opl
from apps.third.clients import xxClient
from apps.third.clients import dhClient
from apps.third.models import TDevice
from apps.third.tapis import xxapis
from django.utils import timezone
import time
from django.utils import timezone
@shared_task
@ -46,7 +51,8 @@ def handle_xx_event_3(name: str, area: Area):
'cate': cate,
'event': event
})
notify_event(event)
voice_msg = area.name + '下有' + str(area.count) + '人,' + cate.name + ',请及时处理'
notify_event(event, voice_msg=voice_msg)
@shared_task
@ -67,3 +73,55 @@ def check_event_timeout():
if cate.hanle_minute > 0 and (timezone.now()-i.create_time).seconds > cate.hanle_minute * 60:
i.is_timeout = True
i.save()
@shared_task
def snap_and_analyse(code: str, algo_codes: list, opl_id: str):
global_img_o = dhClient.snap(code)
happen_time = timezone.now()
vchannel = TDevice.objects.filter(code=code).first()
ec_codes = algo_handle(algo_codes, data={}) # 算法处理返回的事件结果
if ec_codes:
# 获取本次所有发生事件种类
ecs = EventCate.objects.filter(code__in=ec_codes)
obj_cate = 'other'
ep = None
if 'helmet' in ec_codes:
# 如果存在安全帽事件
# 尝试以图搜图找到当事人
res = dhClient.face_search(path=global_img_o)
if res and res[0]:
ep = Employee.objects.filter(id_number=res[0]['identity']).first()
if ep:
obj_cate = 'people'
event = Event()
event.global_img = save_dahua_pic(global_img_o)
if vchannel:
event.vchannel = vchannel
event.area = vchannel.area
event.obj_cate = obj_cate
event.employee = ep
event.happen_time = happen_time
event.opl = Opl.objects.get(id=opl_id)
event.save()
for i in ecs:
Eventdo.objects.get_or_create(cate=i, event=event, defaults={
'cate': i,
'event': event
})
if event:
notify_event(event)
@shared_task
def opl_task(vc_codes: list, opl_id: str):
"""作业监控任务
"""
opl_cate = Opl.objects.get(id=opl_id).cate
# 找到加载的算法
algo_codes = list(EventCate.objects.filter(opl_cates=opl_cate).values_list('code', flat=True))
while True:
for i in vc_codes:
snap_and_analyse.delay(i, algo_codes, opl_id)
time.sleep(2)
time.sleep(4)

View File

@ -75,7 +75,7 @@ class EventViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSet):
perms_map = {'get': '*'}
queryset = Event.objects.all()
serializer_class = EventSerializer
select_related_fields = ['area', 'employee', 'handle_user']
select_related_fields = ['area', 'employee', 'handle_user', 'vchannel']
prefetch_related_fields = ['cates']
filterset_class = EventFilterSet

View File

@ -10,7 +10,7 @@ class ClockRecordFilterSet(filters.FilterSet):
class Meta:
model = ClockRecord
fields = ['employee', 'create_time_start', 'create_time_end', 'year', 'month']
fields = ['employee', 'create_time_start', 'create_time_end', 'year', 'month', 'type']
def filter_year(self, queryset, name, value):
return queryset.filter(create_time_date__year=value)

View File

@ -1,7 +1,7 @@
from django.db import models
from apps.system.models import Post, User
from apps.utils.models import BaseModel, CommonADModel, CommonAModel, CommonBModel
from apps.utils.models import BaseModel, CommonAModel, CommonBModel
class Employee(CommonBModel):

View File

@ -114,7 +114,7 @@ class EmployeeNotWorkRemarkSerializer(ModelSerializer):
class ClockRecordListSerializer(serializers.ModelSerializer):
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
employee_ = EmployeeSimpleSerializer(source='employee', read_only=True)
class Meta:
model = ClockRecord

View File

@ -201,7 +201,7 @@ class HrmService:
if id_number:
ep = Employee.objects.filter(id_number=id_number, type="employee").first()
# 如果是内部员工创建上班打卡记录(更新)
if ep and ep.is_at_work is False:
if ep and ep.is_atwork is False:
now = timezone.now()
cr_10 = ClockRecord.objects.filter(type=10, employee=ep, create_time__year=now.year, create_time__month=now.month, create_time__day=now.day).first()
if cr_10:
@ -217,7 +217,8 @@ class HrmService:
cr_10.trigger = 'door'
cr_10.detail = data['info']['extend']
cr_10.save()
ep.is_at_work = True
ep.is_atwork = True
ep.last_check_time = now
ep.save()
elif data['info']['extend']['enterOrExit'] == "2":
# 如果是出门
@ -225,7 +226,7 @@ class HrmService:
if id_number:
ep = Employee.objects.filter(id_number=id_number, type="employee").first()
# 如果是内部员工创建下班打卡记录(更新)
if ep and ep.is_at_work:
if ep and ep.is_atwork:
now = timezone.now()
cr_20 = ClockRecord.objects.filter(type=20, employee=ep, create_time__year=now.year, create_time__month=now.month, create_time__day=now.day).first()
if cr_20:
@ -241,5 +242,6 @@ class HrmService:
cr_20.trigger = 'door'
cr_20.detail = data['info']['extend']
cr_20.save()
ep.is_at_work = False
ep.is_atwork = False
ep.last_check_time = now
ep.save()

View File

@ -208,6 +208,7 @@ class ClockRecordViewSet(ListModelMixin, CustomGenericViewSet):
permission_classes = [AllowAny]
queryset = ClockRecord.objects.all()
select_related_fields = ['employee']
search_fields = ['employee__name', 'employee__number']
serializer_class = ClockRecordListSerializer
filterset_class = ClockRecordFilterSet
ordering = ['-pk']

View File

@ -0,0 +1,29 @@
# Generated by Django 3.2.12 on 2022-08-12 09:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('third', '0009_tlog_errors'),
('opm', '0002_initial'),
]
operations = [
migrations.AddField(
model_name='operation',
name='cates',
field=models.ManyToManyField(through='opm.Opl', to='opm.OplCate'),
),
migrations.AddField(
model_name='operation',
name='vchannels',
field=models.ManyToManyField(to='third.TDevice', verbose_name='监控所用摄像头'),
),
migrations.AddField(
model_name='opl',
name='mtask_id',
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='视频监控任务ID'),
),
]

View File

@ -1,5 +1,6 @@
from django.db import models
from apps.system.models import User
from apps.third.models import TDevice
from apps.utils.models import BaseModel, CommonADModel, CommonAModel, CommonBDModel
@ -56,6 +57,8 @@ class Operation(CommonBDModel):
coordinator = models.ForeignKey('system.user', verbose_name='业务部门协调员',
on_delete=models.CASCADE)
state_work = models.CharField('生产状态', max_length=20, help_text='运行/停机/检修')
cates = models.ManyToManyField(OplCate, through='opm.opl')
vchannels = models.ManyToManyField(TDevice, verbose_name='监控所用摄像头')
class Opl(CommonBDModel):
@ -114,6 +117,7 @@ class Opl(CommonBDModel):
ticket = models.OneToOneField('wf.ticket', verbose_name='关联工单',
on_delete=models.CASCADE,
null=True, blank=True)
mtask_id = models.CharField('视频监控任务ID', max_length=200, null=True, blank=True)
class OplWorker(BaseModel):

View File

@ -60,6 +60,7 @@ class OperationDetailSerializer(CustomModelSerializer):
dept_bus_ = DeptSimpleSerializer(source='dept_bus', read_only=True)
coordinator_ = UserSimpleSerializer(source='coordinator', read_only=True)
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
cates_ = OplCateSimpleSerializer(source='cates', read_only=True, many=True)
class Meta:
model = Operation

View File

@ -1,4 +1,6 @@
from apps.ecm.tasks import opl_task
from apps.opm.models import Operation, Opl, OplWorker
from apps.third.models import TDevice
from apps.wf.models import Ticket, Transition
@ -53,13 +55,35 @@ def bind_opl(ticket: Ticket, transition: Transition, new_ticket_data: dict):
def opl_audit_end(ticket: Ticket):
# 任务执行1
opl = Opl.objects.get(ticket=ticket)
op = opl.operation
if op.state == Operation.OP_AUDIT:
op.state = Operation.OP_WORK
op.state = Operation.OP_WAIT
op.save()
# 授予相关工作人员区域进入权限
# worker_ep_ids = list(OplWorker.objects.filter(opl=opl).values_list('worker__id', flat=True))
# 发送通知
def opl_start(ticket: Ticket):
# 任务执行2 开始许可证作业
opl = Opl.objects.get(ticket=ticket)
op = opl.operation
if op.state == Operation.OP_WAIT:
op.state = Operation.OP_WORK
op.save()
# 给摄像头加载循环拍照算法
# 找到作业点的摄像头, 如果指定摄像头就用指定的摄像头
if op.vchannels:
vc_codes = list(op.vchannels.all().values_list('code', flat=True))
else:
vc_codes = list(TDevice.objects.filter(type=TDevice.DEVICE_VCHANNEL, area=op.area).values_list('code', flat=True))
opl_id = opl.id
task = opl_task.delay(vc_codes, opl_id)
opl.mtask_id = task.task_id
opl.save()

View File

@ -4,16 +4,25 @@ from apps.opm.models import Operation, Opl
from apps.utils.tasks import CustomTask
from celery import shared_task
from apps.wf.models import State, Ticket
from apps.wf.models import Ticket
@shared_task(base=CustomTask)
def opl_end(ticket_id):
"""
作业关闭时执行
作业许可证关闭时执行
"""
ticket = Ticket.objects.get(id=ticket_id)
operation = ticket.opl.operation
opl = ticket.opl
if opl.mtask_id:
from celery.app.control import Control
from server.celery import app
celery_control = Control(app=app)
# 关闭作业视频监控任务
celery_control.revoke(opl.mtask_id, terminate=True)
opl.mtask_id = None
opl.save()
operation = opl.operation
opls = Opl.objects.filter(operation=operation)
opls.filter(ticket=None).delete() # 删除无用许可证
states = opls.values_list('ticket__state__type', flat=True)
@ -24,19 +33,19 @@ def opl_end(ticket_id):
operation.save()
@shared_task(base=CustomTask)
def opl_audit_start(ticket_id):
operation = Opl.objects.get(ticket__id=ticket_id).operation
if operation.state == Operation.OP_CREATE:
operation.state = Operation.OP_AUDIT
operation.save()
# @shared_task(base=CustomTask)
# def opl_audit_start(ticket_id):
# operation = Opl.objects.get(ticket__id=ticket_id).operation
# if operation.state == Operation.OP_CREATE:
# operation.state = Operation.OP_AUDIT
# operation.save()
@shared_task(base=CustomTask)
def opl_audit_end(ticket_id):
opl = Opl.objects.get(ticket__id=ticket_id)
operation = opl.operation
if operation.state == Operation.OP_AUDIT:
operation.state = Operation.OP_WORK
operation.save()
# @shared_task(base=CustomTask)
# def opl_audit_end(ticket_id):
# opl = Opl.objects.get(ticket__id=ticket_id)
# operation = opl.operation
# if operation.state == Operation.OP_AUDIT:
# operation.state = Operation.OP_WORK
# operation.save()
# 授予区域或围栏权限

View File

@ -31,6 +31,7 @@ class OperationViewSet(CustomModelViewSet):
serializer_class = OperationDetailSerializer
retrieve_serializer_class = OperationDetailSerializer
select_related_fields = ['area', 'dept_bus', 'dept_ter', 'coordinator']
prefetch_related_fields = ['cates']
filterset_fields = ['state', 'opl_operation__cate', 'area', 'create_by']
def update(self, request, *args, **kwargs):

View File

@ -10,7 +10,7 @@ from rest_framework.exceptions import APIException, ParseError
from apps.third.errors import DH_REQUEST_ERROR
from apps.third.models import Tlog
from apps.utils.my_rsa import encrypt_data
from apps.utils.tools import print_roundtrip
from apps.utils.tools import convert_to_base64, print_roundtrip
from django.utils.timezone import now
from apps.third.tapis import dhapis
@ -135,13 +135,17 @@ class DhClient:
返回完整访问地址
"""
json_data = {
"deviceCode": "1000038",
"operation": "generalJsonTransport",
"params": "{\"method\":\"dev.snap\",\"id\":123,\"params\":{\"DevID\":\"1000038\",\"DevChannel\":0,\"PicNum\":1,\"SnapType\":1,\"CmdSrc\":0}}",
"deviceCode": "1000093",
"operation": "generalJsonTransport"
}
if '$' in code:
d_code = code.split('$')[0]
json_data['deviceCode'] = d_code
json_data['params'] = '{\"method\":\"dev.snap\",\"id\":123,\"params\":{\"DevID\":\"' + \
str(d_code) + '\",\"DevChannel\":0,\"PicNum\":1,\"SnapType\":1,\"CmdSrc\":0}}'
_, res = self.request(**dhapis['dev_snap'], json=json_data)
res = json.loads(res)
return self.get_full_pic(res['params']['PicInfo'])
def get_password_token(self):
_, res = self.request(**dhapis['oauth_key'])
@ -156,3 +160,104 @@ class DhClient:
})
_, res2 = self.request(**dhapis['oauth_token'], json=res)
return res2
def face_search(self, path: str):
"""人像库检索
Args:
path (str): 图片地址
返回第一个识别结果
"""
base64img = convert_to_base64(path)
json_data = {
"base64Img": base64img,
"devType": 1,
"deviceCodes": ["1000038"],
"groupIds": ["100001"],
"searchGroupType": 2,
"threshold": "80"
}
_, res = self.request(**dhapis['face_search'], json=json_data)
return res['pageData']
# 返回的识别结果是从右往左
"""
"pageData": [
{
"id": null,
"devId": "1000038",
"channelId": null,
"channelSeq": null,
"channelName": null,
"faceLibId": "1",
"libImgUrl": "6ad010cf-ce45-11ec-9715-e4246c7d1635/20220805/63/dsf_8c2487c1-14a1-11ed-880a-e4246c7d1635_2551349_2624751.jpg",
"faceImgUrl": null,
"hitImgUrl": null,
"identity": "342422199004040175",
"name": "曹前明",
"sex": "",
"nation": null,
"bornYear": null,
"age": null,
"glasses": null,
"fringe": null,
"similarity": 99,
"recTime": null,
"mask": null,
"beard": null,
"glass": null,
"maskStr": null,
"beardStr": null,
"glassStr": null,
"featureStr": "其他 ",
"groupName": "内部库1",
"groupType": 3,
"groupTypeStr": "内部库",
"identityType": 1,
"identityTypeStr": "身份证",
"birthday": null,
"searchGroupType": 2,
"birthdayStr": "2022-07-14",
"deviceName": "ivs服务器",
"personCode": "123"
},
{
"id": null,
"devId": "1000038",
"channelId": null,
"channelSeq": null,
"channelName": null,
"faceLibId": "1",
"libImgUrl": "6ad010cf-ce45-11ec-9715-e4246c7d1635/20220805/63/dsf_8c2487c1-14a1-11ed-880a-e4246c7d1635_2624751_2701750.jpg",
"faceImgUrl": null,
"hitImgUrl": null,
"identity": "371324199502156548",
"name": "石静",
"sex": "",
"nation": null,
"bornYear": null,
"age": null,
"glasses": null,
"fringe": null,
"similarity": 96,
"recTime": null,
"mask": null,
"beard": null,
"glass": null,
"maskStr": null,
"beardStr": null,
"glassStr": null,
"featureStr": "其他 ",
"groupName": "内部库1",
"groupType": 3,
"groupTypeStr": "内部库",
"identityType": 1,
"identityTypeStr": "身份证",
"birthday": null,
"searchGroupType": 2,
"birthdayStr": "2022-06-24",
"deviceName": "ivs服务器",
"personCode": "shijing"
}
]
"""

View File

@ -115,6 +115,10 @@ dhapis = {
"oauth_token": {
"url": "/evo-apigw/evo-oauth/1.0.0/oauth/extend/token",
"method": "post"
},
"face_search": {
"url": "/evo-apigw/evo-face/faceSearch/third/faceSearchSync",
"method": "post"
}
}

View File

@ -21,13 +21,15 @@ from django.conf import settings
class DahuaTestView(MyLoggingMixin, APIView):
"""
"""大华测试接口
大华测试接口
"""
permission_classes = [IsAuthenticated]
def get(self, request, *args, **kwargs):
res = dhClient.get_password_token()
res = dhClient.face_search(path='/media/2022/07/13/three.jpg')
return Response(res)

View File

@ -204,7 +204,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
json = {
"pageNum": 1,
"pageSize": 1000,
'channelTypeList': ["1"]
'channelTypeList': ["1"],
'includeSubOwnerCodeFlag': True
}
_, res = dhClient.request(**dhapis['channel_list'], json=json)
if res.get('pageData', None):
@ -229,7 +230,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
json = {
"pageNum": 1,
"pageSize": 1000,
'channelTypeList': ["7"]
'channelTypeList': ["7"],
'includeSubOwnerCodeFlag': True
}
_, res = dhClient.request(**dhapis['channel_list'], json=json)
if res.get('pageData', None):
@ -302,7 +304,10 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
视频通道列表
"""
request.data.update({'channelTypeList': ["1"]})
request.data.update({
'channelTypeList': ["1"],
'includeSubOwnerCodeFlag': True
})
_, res = dhClient.request(**dhapis['channel_list'], json=request.data)
codes = []
if res.get('pageData', None):
@ -349,7 +354,10 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
闸机通道列表
"""
request.data.update({'channelTypeList': ["7"]})
request.data.update({
'channelTypeList': ["7"],
'includeSubOwnerCodeFlag': True
})
_, res = dhClient.request(**dhapis['channel_list'], json=request.data)
codes = []
if res.get('pageData', None):

View File

@ -2,6 +2,10 @@ import textwrap
import random
import string
from datetime import datetime
from django.conf import settings
import base64
import requests
from io import BytesIO
def print_roundtrip(response, *args, **kwargs):
@ -40,6 +44,19 @@ def timestamp_to_time(millis):
return datetime.fromtimestamp(millis)
def convert_to_base64(path: str):
"""给定图片转base64
Args:
path (str): 图片地址
"""
if path.startswith('http'): # 如果是网络图片
return str(base64.b64encode(BytesIO(requests.get(url=path).content).read()), 'utf-8')
else:
with open(settings.BASE_DIR + path, 'rb') as f:
return str(base64.b64encode(f.read()), 'utf-8')
def p_in_poly(p, poly):
px = p['x']
py = p['y']

View File

@ -56,19 +56,23 @@ class VpeopleCreateSerializer(CustomModelSerializer):
fields = ['visit', 'visitor', 'is_main']
def create(self, validated_data):
if validated_data['visit'].state != Visit.V_CREATE:
visit = validated_data['visit']
visitor = validated_data['visitor']
if visit.state != Visit.V_CREATE:
raise ParseError('项目非创建状态不可新增成员')
if validated_data['visit'].level == 10:
visitor = validated_data['visitor']
if visit.level == 10:
if visitor.id_number and visitor.photo:
pass
else:
raise ParseError('访客信息不全,请完善后再试')
if Vpeople.objects.filter(visit=validated_data['visit'], visitor=validated_data['visitor']).exists():
if Vpeople.objects.filter(visit=visit, visitor=visitor).exists():
raise ParseError('该访客已选中')
ins = super().create(validated_data)
if ins.is_main:
Vpeople.objects.filter(visit=validated_data['visit']).exclude(id=ins.id).update(is_main=False)
Vpeople.objects.filter(visit=visit).exclude(id=ins.id).update(is_main=False)
if visit.level == 10:
visit.count_people = Vpeople.objects.filter(visit=visit).count()
visit.save()
return ins