Python、OpenCV实现的电脑远程拍照控制系统,照片并以web形式发布

Python、OpenCV实现的电脑远程拍照控制系统,照片并以web形式发布,第1张

一、题目:

利用OpenCV等,自行Python编程实现一个远程拍照控制系统,该系统包括摄像头端(Server)和用户端(Client)。Server端运行.py程序,接受Client控制,实现拍照、存储在本地,同时提供Web服务,可以将照片以Web方式发布;Client端运行.py程序,通过按钮或输入特殊字符控制Server拍照,并且可利用浏览器访问Server即时照片。要求至少在局域网内成功运行,鼓励内网穿透,在Internent上测试执行。


二、本程序实现功能

本程序实现功能:

程序通过多线程实现了多个客户端可以同时远程拍照,并以客户端的mac地址作为客户端id和图片的名称,拍完照片后并通过加密返回给客户端一个密钥。然后服务器也建立一个线程,专门通过flask发布照片。客户端通过网页凭密钥访问照片,服务器解密密钥,从而得到需要访问照片的名称,以此多个客户端只可以访问到自己所拍的照片。照片以web形式发布。


三、建议及注意事项

建议:

建议在虚拟环境里安装包依赖、运行程序

注意:

本程序仅适配于局域网,外网请自行配置内网穿透

本程序服务端客户端运行系统是Win10

Sever.py端的Python解释器版本3.6.6。不得用高版本,否则,opencv报错

切记包版本不要更改,尤其是numpy,否则opencv报错

文末有程序运行过程的说明,仅供参考


四、文件夹目录


五、源代码:

Server.py包依赖

文件名:requirements.txt

click==8.0.4
colorama==0.4.4
dataclasses==0.8
Flask==2.0.3
importlib-metadata==4.8.3
itsdangerous==2.0.1
Jinja2==3.0.3
MarkupSafe==2.0.1
numpy==1.19.5
opencv-python==3.4.1.15
typing-extensions==4.1.1
Werkzeug==2.0.3
zipp==3.6.0
Server.py
from concurrent.futures import thread
from distutils.log import debug
from flask import Flask, render_template, request
import cv2
import numpy as np
import threading
import socket
import os
#加密字典对照
dict_Password={'0':'L','1':'X','2':'H','3':'0',\
               '4':'1','5':'9','6':'3','7':'Y',\
               '8':'J','9':'2','a':'4','b':'Q',\
               'c':'Z','d':'6','e':'D','f':'8'}

#这是加密函数,对需要加密的字符串进行加密,返回值为加密后的字符串
def data_Encrypt(key):
    i_key=''
    for x in key: #遍利需要加密的字符串每个元素,并将每个元素(键)按加密字典对照表(10-13行)得到其对应的值,然后拼接成字符串      
        i_key=i_key+dict_Password[x]
    return i_key

#这是解密函数,对需要解密的字符串进行解密,返回值为解密后的字符串
def data_Decrypt(key):
    i_key=''
    for x in key:#遍利需要解密的字符串的每个元素,每个元素通过值来查找获得对应的键。 然后拼接成字符串  
        k2 = [k for k, v in dict_Password.items() if v == x]
        k2=''.join(k2)
        i_key=i_key+k2
    return i_key

#这是一个拍照函数,传入的id用以给图片命名
def camera_Save_Fun(id):
    cap = cv2.VideoCapture(0)   
    ret, frame = cap.read()
    cv2.imwrite(r"static/"+id+".jpg",frame)
    cap.release()
    cv2.destroyAllWindows()


#这是一个flask服务,并将其放到一个线程里,用以提供web服务
def flask_Thead_Fun():
    # 创建Flask对象
    app = Flask(__name__)
    # route()函数告诉那个URL执行哪个函数
    @app.route("/",methods=['GET', 'POST'])
    def index():
        if request.method == 'POST':#提交表单后,浏览器向服务器发送一个post请求,其中包含参数,这是处理post请求的部分
            print('接收的密钥值为'+request.form.get('key'))#request.form.get('key')是为了获得post中的参数,即密钥
            img_id=data_Decrypt(request.form.get('key'))#将密钥进行解密,解密后的值赋给img_id,img_id的意思是本地图片的名字
            if os.path.exists("static/"+img_id+".jpg"):#if语句用来判断本地图片(img_id)是否存在
                sys_Info="您所拍的照片如下:"            #如果存在,将存在的提示信息赋值给sys_Info
            else:                                     #如果不存在,将不存在的提示信息赋值给sys_Info
                sys_Info="您还未拍照片或照片已删除,请重拍"
            #将图片是否存在的信息、本地图片的id(img_id)赋值给 HTML,然后生成静态网页,
            #key_value=request.form.get('key') 是为了刷新html后,表单中的值(即密钥)依然存在,不用再输入一遍
            return render_template('ShowImg.html',info= sys_Info,img_Id=img_id,key_value=request.form.get('key'))
        else:
            return render_template('index.html')#浏览器第一次访问肯定是get请求,所以返回的是只含有表单的网页,
                                                #提交表单之后就是post请求,就可以处理post参数(即密钥)了
    if __name__ == "__main__":
        app.run(host="0.0.0.0",debug = False) #可访问127.0.0.1:5000,或者localhost:5000
    


#以下两种线程函数实现了,多个客户端可以同时访问服务器进行拍照,通过传来的客户端id(client_id)进行区分不同的客户端,并通过客户端id命名图片
# 拿到客户端id的同时,会加密 客户端id 得到一个密钥(client_id_encrypt),并再发送给客户端,客户端在网页中输入密钥,递交表单,flask会解密,
# 解密后得到正确的客户端id名,即图片的名称,然后就可以访问此电脑拍摄的图片,而不是其他电脑的图片。加密解密是为了更安全

#这是一个管理客户端连接的线程。循环为需要连接的客户端分配一个客户端数据传输的线程    
def client_Connect_Thead_Fun():  
    while True:
        conn, client_addr = server_sk.accept()
        
        client_data_Thead = threading.Thread(target=client_data_Thead_Fun,args=(conn,))#为需要连接的客户端分配一个客户端数据传输的线程
        client_data_Thead.start()

#这是一个客户端数据传输的线程
def client_data_Thead_Fun(conn):
   
    #接收客户端id
    data_client = conn.recv(1024)
    client_id=data_client.decode('utf-8')
    if client_id == '':
        pass
    else:
        print('服务器已连接ID为{0}的客户端'.format(client_id))

        client_id_encrypt=data_Encrypt(client_id)#加密客户端id,得到密钥,赋给client_id_encrypt
        message="您的密钥为: "+client_id_encrypt#将密钥发送给客户端
        conn.send(message.encode('utf-8'))
        #异常处理是因为如果客户端直接断开连接,服务器不会崩溃
        try:
            while True:
                # 接收客户端信息
                data_client = conn.recv(1024)
                print(data_client.decode('utf-8'))
                #客户端发来的信息若是y,就拍照,是deleteImg,就删除照片,是exit,就跳出循环,关闭和客户端的连接
                if data_client.decode('utf-8') == 'y':
                    camera_Save_Fun(client_id)#调用拍照函数,将客户端id传给此函数
                    message="提示:您的密钥为"+client_id_encrypt+"请访问xxxxxx查看照片"#信息提示传给客户端
                    conn.send(message.encode('utf-8'))
                elif data_client.decode('utf-8') == 'deleteImg':
                    try:#异常处理。处理文件不存在的异常,并将是否删除成功的信息传给客户端
                        os.remove("static/"+client_id+".jpg")
                        message="删除图片成功"
                        conn.send(message.encode('utf-8'))
                    except FileNotFoundError:
                        print('无法删除:系统找不到static/{0}.jpg文件'.format(client_id))
                        message="无法删除,系统找不到图片文件"
                        conn.send(message.encode('utf-8'))
                elif data_client.decode('utf-8') == 'exit':           
                    break  #跳出循环
                else:
                    message="输入错误,请重新输入"
                    conn.send(message.encode('utf-8'))
        
            conn.close()
            print('服务器已断开ID为{0}的客户端'.format(client_id))
        except:
            print('ID为{0}的客户端强迫关闭了现有的连接'.format(client_id))



#从这里开始运行!!!

server_sk = socket.socket()
# 设置给定套接字选项的值。
server_sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 把地址绑定到套接字
server_sk.bind(('', 8000))#默认8000为本机socket通信端口
# 监听链接
server_sk.listen()
# 接受客户端链接

#启动flask和管理客户端连接的线程
if __name__ == '__main__':
    flask_Thead = threading.Thread(target=flask_Thead_Fun,args=())
    client_Connect_Thead = threading.Thread(target=client_Connect_Thead_Fun,args=())
    flask_Thead.start()
    client_Connect_Thead.start()
    

Client.py

若服务器和客户端运行在同一局域网,请将xxxxxxxx改为服务器的局域网IP,否则改为公网IP

import socket
import uuid

#获取本机的mac并返回
def get_mac_address():
    mac=uuid.UUID(int = uuid.getnode()).hex[-12:]
    return "".join([mac[e:e+2] for e in range(0,11,2)])


client_sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

#进行连接服务器
#client_sk.connect(('xxxxxx', 0000))#公网IP端口
client_sk.connect(('xxxxxxxx', 8000))#局域网服务器的IP及服务器socket端口,端口默认是8000
#将mac作为客户端id。发送给服务器,然后接收服务器发来的密钥和提示信息(接受的信息赋给data_server),密钥用以访问拍摄的图片
message=get_mac_address()
client_sk.send(message.encode('utf-8'))
data_server=client_sk.recv(1024)#接受服务端的信息,最大数据为1k
print(data_server.decode('utf-8'))

#循环
while True:
    message=''
    message=input('拍照[y/deleteImg/exit]')
    client_sk.send(message.encode('utf-8'))#将发送的数据进行编码
    if message=='exit':
        client_sk.close()
        print('客户端已退出')
        break
    data_server=client_sk.recv(1024)#接受服务端的信息,最大数据为1k
    print(data_server.decode('utf-8'))

index.html




    
    1910300105



    


请输入查询密钥:

ShowImg.html




    
    1910300105



    


请输入查询密钥:

{key_value}}>


{{info}}


{img_Id}}.jpg">

六、源代码运行过程说明

服务器程序运行过程:

首先创建套接字的基本信息,然后给flask分配一个线程并启动,然后再给负责客户端连接的函数分配一个线程,用于检测是否有其他客户端连接进来。若有客户端连接进来,那么在为其分配一个数据传输的线程,用来传输数据。在数据传输线程中,首先会收到来自于客户端的mac地址即id,然后。服务器端进行加密,返回给客户端一个密钥,然后接下来会有一个异常处理作用是为了如果。客户端强迫关闭连接的话,服务器端程序不会崩溃。在异常处理的try里面,是一个循环用来循环检测客户端是否发来数据,并判断数据是什么,如果是y,则调用拍照函数,并将客户端的ID即mac作为拍照后图片的名称 ,如果是deleteImg,则删除图片,这里也有一个对,如果图片不存在的异常处理。如果是exit,则跳出循环,关闭与客户端的连接,然后此线程关闭。如果客户端输入的是其他信息,则向客户端发送输入错误,请重新输入。


flask运行过程:

客户端访问网站会返回给浏览器初始页面,然后客户端输入,你要点击查询后,flask会接收到post的请求,然后解密后得到客户端ID既图片的名称,判断此图片是否在服务器中,然后将相应的提示信息赋给变量。然后将各参数传给html,然后返回html


客户端运行程序过程:

建立套接字 获取本机的mac地址,然后接收服务器发来的信息,然后进入循环

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/715611.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存