491 lines
21 KiB
Python
491 lines
21 KiB
Python
import os
|
||
from datetime import datetime
|
||
from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData, DateTime,TIMESTAMP
|
||
import psycopg2
|
||
import cv2
|
||
import numpy as np
|
||
from numpy.fft import fft2, fftshift, ifft2, ifftshift
|
||
import matplotlib.pyplot as plt
|
||
from PIL import Image, ImageOps
|
||
import random
|
||
from skimage.measure import label, regionprops
|
||
import math
|
||
import json
|
||
|
||
# 创建连接引擎
|
||
engine = create_engine('postgresql://postgres:!1q2w3E*@8.134.85.73:5432/postgres')
|
||
# 连接数据库
|
||
connection = engine.connect()
|
||
print("Connection to PostgreSQL DB successful")
|
||
# 声明表结构
|
||
metadata = MetaData()
|
||
qrcode_data = Table('qrcode_data', metadata,
|
||
Column('key', String),
|
||
Column('circles', String),
|
||
# createdate 时间类型
|
||
Column('createdate', TIMESTAMP)
|
||
)
|
||
|
||
def create_filter_with_only_circles_and_generate(size, cutoff_radius, num_circles, circle_radius):
|
||
"""
|
||
创建一个仅包含指定数量圆形的滤波器。
|
||
|
||
参数:
|
||
size: 滤波器的大小(宽度和高度相同)。
|
||
cutoff_radius: 低频区域的半径,确保所有圆都在此区域内。
|
||
num_circles: 滤波器中要生成的圆的数量。
|
||
circle_radius: 圆的半径。
|
||
|
||
返回值:
|
||
一个二进制滤波器数组,其中圆的区域值为1,其他区域值为0。
|
||
"""
|
||
filter = np.zeros((size, size)) # 初始化滤波器数组
|
||
center_x, center_y = size // 2, size // 2 # 计算滤波器中心点坐标
|
||
circles = [] # 存储已生成圆的列表
|
||
max_attempts = 1000 # 设置最大尝试次数,以避免无限循环
|
||
|
||
while len(circles) < num_circles and max_attempts > 0: # 循环,直到生成足够数量的不重叠圆
|
||
# 随机生成圆心位置,确保圆完全位于低频区域内
|
||
angle = random.uniform(0, 2 * np.pi)
|
||
r = random.uniform(0, cutoff_radius - circle_radius)
|
||
x = int(center_x + r * np.cos(angle))
|
||
y = int(center_y + r * np.sin(angle))
|
||
|
||
# 检查新生成的圆是否与已存在的圆重叠
|
||
overlapping = False
|
||
for cx, cy, cr in circles:
|
||
if np.sqrt((x - cx) ** 2 + (y - cy) ** 2) < (circle_radius + cr):
|
||
overlapping = True
|
||
break
|
||
|
||
if not overlapping: # 如果新圆不与任何已存在圆重叠,则添加到列表中
|
||
circles.append((x, y, circle_radius))
|
||
max_attempts -= 1
|
||
|
||
# 为每个生成的圆,在滤波器数组中设置对应区域的值为1
|
||
for (x, y, radius) in circles:
|
||
for i in range(-radius, radius + 1):
|
||
for j in range(-radius, radius + 1):
|
||
if np.sqrt(i ** 2 + j ** 2) <= radius:
|
||
filter[x + i, y + j] = 1 # 设置圆形区域的值为1
|
||
|
||
return filter
|
||
|
||
def generate_circles_in_frequency_domain(size, cutoff_radius, num_circles, circle_radius):
|
||
"""
|
||
生成指定数量的圆形,用于频域操作。
|
||
|
||
参数:
|
||
size: 频域的大小(宽度和高度相同)。
|
||
cutoff_radius: 低频区域的半径,确保所有圆都在此区域内。
|
||
num_circles: 要生成的圆的数量。
|
||
circle_radius: 圆的半径。
|
||
|
||
返回值:
|
||
一个列表,包含每个圆的 (中心x坐标, 中心y坐标, 半径) 元组。
|
||
"""
|
||
center_x, center_y = size // 2, size // 2 # 计算频域中心点坐标
|
||
circles = [] # 存储已生成圆的列表
|
||
max_attempts = 1000 # 设置最大尝试次数,以避免无限循环
|
||
|
||
while len(circles) < num_circles and max_attempts > 0: # 循环,直到生成足够数量的不重叠圆
|
||
# 随机生成圆心位置,确保圆完全位于低频区域内
|
||
angle = random.uniform(0, 2 * np.pi)
|
||
r = random.uniform(0, cutoff_radius - circle_radius)
|
||
x = int(center_x + r * np.cos(angle))
|
||
y = int(center_y + r * np.sin(angle))
|
||
|
||
# 检查新生成的圆是否与已存在的圆重叠
|
||
overlapping = False
|
||
for cx, cy, cr in circles:
|
||
if np.sqrt((x - cx) ** 2 + (y - cy) ** 2) < (circle_radius + cr):
|
||
overlapping = True
|
||
break
|
||
|
||
if not overlapping: # 如果新圆不与任何已存在圆重叠,则添加到列表中
|
||
circles.append((x, y, circle_radius))
|
||
max_attempts -= 1
|
||
|
||
return circles
|
||
|
||
def draw_circles_on_frequency_domain(size, circles):
|
||
"""
|
||
在频域图中绘制圆形。
|
||
|
||
参数:
|
||
size: 频域的大小(宽度和高度相同)。
|
||
circles: 包含每个圆的 (中心x坐标, 中心y坐标, 半径) 元组的列表。
|
||
|
||
返回值:
|
||
一个二维数组,表示频域图,其中圆形区域的值为1,其他区域的值为0。
|
||
"""
|
||
frequency_domain_image = np.zeros((size, size)) # 初始化频域图数组
|
||
|
||
# 遍历所有圆并在频域图中绘制它们
|
||
for (x, y, radius) in circles:
|
||
for i in range(-radius, radius + 1):
|
||
for j in range(-radius, radius + 1):
|
||
if i**2 + j**2 <= radius**2: # 判断点是否在圆内
|
||
# 检查绘制点是否在图像范围内
|
||
if 0 <= x + i < size and 0 <= y + j < size:
|
||
frequency_domain_image[x + i, y + j] = 1
|
||
|
||
return frequency_domain_image
|
||
|
||
def find_circles_in_filter(filter_array):
|
||
"""
|
||
从滤波器数组中识别圆形区域,提取每个圆的中心和半径。
|
||
|
||
参数:
|
||
filter_array (ndarray): 一个二维数组,其中圆形区域的值为1,其他为0。
|
||
|
||
返回:
|
||
list: 每个圆的 (中心x坐标, 中心y坐标, 半径) 元组列表。
|
||
"""
|
||
labeled_image = label(filter_array) # 标记连通区域
|
||
regions = regionprops(labeled_image) # 提取区域属性
|
||
circles = []
|
||
for region in regions:
|
||
if region.area >= 5: # 排除太小的区域,假定它们不是我们要找的圆
|
||
radius = np.sqrt(region.area / np.pi) # 计算半径
|
||
circles.append((region.centroid[1], region.centroid[0], radius)) # x, y顺序要反转,因为centroid给出的是(row, col)
|
||
return circles
|
||
|
||
def distribute_points_on_circles(f_shifted, circles, num_points=240):
|
||
"""
|
||
将点均匀分布在每个圆周上。
|
||
|
||
参数:
|
||
f_shifted: 平移处理的函数图像
|
||
circles (list of tuples): 每个元组包含一个圆的 (中心x坐标, 中心y坐标, 半径)
|
||
num_points (int): 每个圆上的点数量,默认为240
|
||
|
||
返回:
|
||
list: 每个圆的点坐标列表,每个元素为一个包含240个点的列表,每个点是(x, y)坐标的元组
|
||
"""
|
||
radians_per_step = 2 * np.pi / num_points # 计算每个步长的弧度值
|
||
print('弧度:', radians_per_step)
|
||
all_circle_points = [] # 存储所有圆的点坐标
|
||
|
||
for center_x, center_y, radius in circles:
|
||
# print('中心坐标:', center_x, center_y)
|
||
circle_points = [] # 存储单个圆的点坐标
|
||
for i in range(num_points):
|
||
theta = i * radians_per_step # 计算当前点的角度弧度
|
||
x = center_x + radius * np.cos(theta) # 极坐标转笛卡尔坐标(x)
|
||
y = center_y + radius * np.sin(theta) # 极坐标转笛卡尔坐标(y)
|
||
#通过笛卡尔坐标计算回角度
|
||
angle_radians = math.atan2(y - center_y, x - center_x)
|
||
angle_degrees = math.degrees(angle_radians)
|
||
#保留angle_degrees小数点后1位,四舍五入
|
||
angle_degrees = round(angle_degrees, 1)
|
||
#计算x,y坐标点的幅度
|
||
amplitude = np.abs(f_shifted[int(x), int(y)])
|
||
#计算x,y坐标点的相位
|
||
phase = np.angle(f_shifted[int(x), int(y)])
|
||
#将当前点的坐标,幅度以及相位打印出来
|
||
# print(f"x: {x}, y: {y}, angle: {angle_degrees}, amplitude: {amplitude}, phase: {phase}")
|
||
# 将当前点的坐标,幅度以及相位添加到列表
|
||
circle_points.append((int(x), int(y), angle_degrees, amplitude, phase)) # 添加当前点的坐标到列表
|
||
all_circle_points.append(circle_points) # 添加该圆的所有点坐标到主列表
|
||
#打印出circle_points中最大的幅度
|
||
# print(f"最大幅度:{max(circle_points, key=lambda x: x[3])[3]}")
|
||
|
||
# 将all_circle_points每个元素的点坐标根据amplitude进行降序排序
|
||
# for i in range(len(all_circle_points)):
|
||
# all_circle_points[i].sort(key=lambda x: x[3], reverse=True)
|
||
|
||
packed_circle_points = []
|
||
|
||
for circle_points in all_circle_points:
|
||
x, y, angles, amplitudes, phase = zip(*circle_points)
|
||
packed_circle_points.append((x, y, angles, amplitudes, phase))
|
||
|
||
return packed_circle_points
|
||
|
||
def degrees_to_radians(degrees):
|
||
"""
|
||
将角度转换为弧度。
|
||
|
||
参数:
|
||
degrees (float): 输入的角度值。
|
||
|
||
返回:
|
||
float: 转换后的弧度值。
|
||
"""
|
||
# 将角度乘以π/180,完成角度到弧度的转换
|
||
radians = degrees * (math.pi / 180)
|
||
return radians
|
||
|
||
# 将水印序列编码为二进制字符串
|
||
def encode_watermark_to_binary(watermark_sequence):
|
||
binary_sequence = []
|
||
for number in watermark_sequence:
|
||
# 初始化一个100位全为'0'的二进制字符串
|
||
binary_100_bit = ['0'] * 100
|
||
# 在数字对应的位置设置'1'
|
||
if 0 <= number < 100:
|
||
binary_100_bit[number-1] = '1'
|
||
# 连接这些位,形成一个100位的二进制字符串
|
||
binary_sequence.append(''.join(binary_100_bit))
|
||
return binary_sequence
|
||
|
||
#解析图片水印
|
||
def process_image_b_component(image_path, circles, watermarks):
|
||
num_points = 240
|
||
img = Image.open(image_path)
|
||
img = np.array(img)
|
||
# 将img缩放到 256*256
|
||
# img = cv2.resize(img, (339,339))
|
||
# img = cv2.resize(img, (500, 500))
|
||
img = cv2.resize(img, (255, 255))
|
||
b_channel = img[:, :, 2]
|
||
# 计算二维DFT并移位,使零频率分量在中心
|
||
f_transform = fft2(b_channel)
|
||
f_shifted = fftshift(f_transform)
|
||
radians_per_step = 2 * np.pi / num_points # 计算每个步长的弧度值
|
||
all_circle_points = [] # 存储所有圆的点坐标
|
||
|
||
for center_x, center_y, radius in circles:
|
||
# print('中心坐标:', center_x, center_y)
|
||
circle_points = [] # 存储单个圆的点坐标
|
||
for i in range(num_points):
|
||
theta = i * radians_per_step # 计算当前点的角度弧度
|
||
x = center_x + radius * np.cos(theta) # 极坐标转笛卡尔坐标(x)
|
||
y = center_y + radius * np.sin(theta) # 极坐标转笛卡尔坐标(y)
|
||
# 通过笛卡尔坐标计算回角度
|
||
angle_radians = math.atan2(y - center_y, x - center_x)
|
||
angle_degrees = math.degrees(angle_radians)
|
||
# 保留angle_degrees小数点后1位,四舍五入
|
||
angle_degrees = round(angle_degrees, 1)
|
||
# 计算x,y坐标点的幅度
|
||
amplitude = np.abs(f_shifted[int(x), int(y)])
|
||
# 计算x,y坐标点的相位
|
||
phase = np.angle(f_shifted[int(x), int(y)])
|
||
# 将当前点的坐标,幅度以及相位打印出来
|
||
print(f"x: {int(x)}, y: {int(y)}, angle: {angle_degrees}, amplitude: {amplitude}, phase: {phase}")
|
||
# 将当前点的坐标,幅度以及相位添加到列表
|
||
circle_points.append((int(x), int(y), angle_degrees, amplitude, phase)) # 添加当前点的坐标到列表
|
||
all_circle_points.append(circle_points) # 添加该圆的所有点坐标到主列表
|
||
|
||
watermark_result = []
|
||
#遍历all_circle_points
|
||
for i in range(len(all_circle_points)):
|
||
print(f"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 第{i + 1}个圆")
|
||
w = watermarks[i]
|
||
isOk = False
|
||
# 将all_circle_points每个元素的点坐标根据amplitude进行降序排序
|
||
all_circle_points[i].sort(key=lambda x: x[3], reverse=True)
|
||
# 打印all_circle_points[i]中每个元素
|
||
for j in range(16): # 只考虑每个圆的前四个最大幅度
|
||
point = all_circle_points[i][j]
|
||
print(f"幅度排名 {j + 1}: x: {point[0]}, y: {point[1]}, 角度: {point[2]}, 幅度: {point[3]}, 相位: {point[4]}")
|
||
# 处理角度,使其在0到360度范围内
|
||
adjusted_angle = point[2] if point[2] >= 0 else point[2] + 360
|
||
# 计算并打印当前角度是圆上的第几份
|
||
fraction_index = adjusted_angle / 1.5 + 1
|
||
if w == fraction_index:
|
||
print(f"水印匹配成功!角度:{adjusted_angle} , 编码:{fraction_index}")
|
||
# 将当前fraction_index添加到结果列表中,保留整数位
|
||
watermark_result.append(int(fraction_index))
|
||
isOk = True
|
||
break
|
||
if isOk == False:
|
||
watermark_result.append(0)
|
||
|
||
return watermark_result, img
|
||
|
||
def calculate_psnr(image1, image2):
|
||
mse = np.mean((image1 - image2) ** 2)
|
||
if mse == 0:
|
||
return float('inf')
|
||
max_pixel = 255.0
|
||
psnr = 20 * np.log10(max_pixel / np.sqrt(mse))
|
||
return psnr
|
||
|
||
def perspective_transform(img_path):
|
||
if not os.path.exists(img_path):
|
||
raise FileNotFoundError(f"Image file '{img_path}' not found.")
|
||
# 通过cv2加载图片
|
||
img = cv2.imread(img_path)
|
||
if img is None:
|
||
raise FileNotFoundError(f"Image file '{img_path}' not found or could not be read.")
|
||
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
||
# 复制图片
|
||
img_copy = img.copy()
|
||
# 将图片转灰度图
|
||
img_copy = cv2.cvtColor(img_copy, cv2.COLOR_BGR2GRAY)
|
||
# 黑白颜色反转
|
||
img_copy = cv2.bitwise_not(img_copy)
|
||
wechatqr = cv2.wechat_qrcode.WeChatQRCode("wechat_qrcode/detect.prototxt", "wechat_qrcode/detect.caffemodel",
|
||
"wechat_qrcode/sr.prototxt", "wechat_qrcode/sr.caffemodel")
|
||
res, points = wechatqr.detectAndDecode(img_copy)
|
||
# 在原图上标记二维码的角点
|
||
if len(res) > 0:
|
||
# for point in points[0]:
|
||
# cv2.circle(img, tuple(int(i) for i in point), 10, (255, 0, 0), -1) # 红色圆点,半径为10
|
||
point = points[0]
|
||
width = max(np.linalg.norm(point[0] - point[1]), np.linalg.norm(point[2] - point[3]))
|
||
height = max(np.linalg.norm(point[1] - point[2]), np.linalg.norm(point[3] - point[0]))
|
||
# 不添加边距
|
||
points_dst = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=point.dtype)
|
||
# 生成变换矩阵
|
||
matrix = cv2.getPerspectiveTransform(point, points_dst)
|
||
# 应用透视变换,纠正图像
|
||
corrected_image = cv2.warpPerspective(img, matrix, (int(width), int(height)))
|
||
|
||
return corrected_image, img, res[0] # 返回校正后的图像和标记后的原图
|
||
|
||
return None, img, None # 如果没有检测到二维码,仅返回原图
|
||
|
||
|
||
def exec_image_result(img_path):
|
||
# 设置图像大小和截止频率半径
|
||
cutoff_radius = 80
|
||
# 在低通滤波器中添加8个随机圆形区域
|
||
circle_radius = 15 # 每个圆的半径
|
||
num_circles = 8 # 圆形数量
|
||
alpha = 1.5
|
||
# 加载图片
|
||
# img_path = 'qr8_1000.png'
|
||
# img = Image.open(img_path)
|
||
# img = np.array(img)
|
||
corrected_image, img, qr_res = perspective_transform(img_path)
|
||
# 复制一份原图
|
||
img_copy = corrected_image.copy()
|
||
# 获取img_copy的size
|
||
N, M, _ = img_copy.shape
|
||
print(f"img_copy size: {json.dumps(img_copy.shape)}")
|
||
# 提取B通道
|
||
b_channel = corrected_image[:, :, 2]
|
||
N, M = b_channel.shape
|
||
# 计算二维DFT并移位,使零频率分量在中心
|
||
f_transform = fft2(b_channel)
|
||
f_shifted = fftshift(f_transform)
|
||
# watermark_sequence = [77, 23, 51, 48, 44, 55, 22, 66] # 示例数字
|
||
watermark_sequence = [int(qr_res[i:i + 2]) for i in range(0, len(qr_res), 2)]
|
||
encoded_watermark = encode_watermark_to_binary(watermark_sequence)
|
||
# 展开所有的二进制编码成一个长字符串
|
||
flattened_encoded_watermark = ''.join(encoded_watermark)
|
||
print(flattened_encoded_watermark)
|
||
# 生成了指定数量的位于频域中的圆
|
||
circles = generate_circles_in_frequency_domain(b_channel.shape[0], cutoff_radius, num_circles, circle_radius)
|
||
# 绘制圆形
|
||
frequency_domain_image = draw_circles_on_frequency_domain(b_channel.shape[0], circles)
|
||
# 将circles转成 json
|
||
circles_json = json.dumps(circles)
|
||
print(circles_json)
|
||
# 获取当前时间
|
||
print(datetime.now())
|
||
# 保存数据
|
||
new_qr_data = qrcode_data.insert().values(key=json.dumps(watermark_sequence), circles=json.dumps(circles),
|
||
createdate=datetime.now())
|
||
connection.execute(new_qr_data)
|
||
connection.commit()
|
||
# connection.close()
|
||
distributed_points = distribute_points_on_circles(f_shifted, circles, 240)
|
||
# 总幅度
|
||
f_amplitudes = np.abs(f_shifted)
|
||
# 总相位
|
||
f_phase = np.angle(f_shifted)
|
||
for circle_index, (x, y, angles, amplitudes, phase) in enumerate(distributed_points):
|
||
# 根据指定的圆圈索引,从编码后的水印中获取对应的元素
|
||
cw = encoded_watermark[circle_index]
|
||
# 获取amplitudes的最大值
|
||
max_amplitude = max(amplitudes)
|
||
print(f"圆 {circle_index + 1} 的数据: 编码:{cw} ,最大幅度:{max_amplitude}")
|
||
# 这里我们可以访问每个圆的所有点的坐标、角度和幅度
|
||
for i in range(len(x)): # 假设每个圆有相同数量的点,例如240个
|
||
# print(f"点 {i + 1}: x = {int(x[i])}, y = {int(y[i])}, 角度 = {angles[i]}, 幅度 = {amplitudes[i]}, 相位 = {phase[i]}")
|
||
if i < len(cw): # 确保不会超出水印信息的长度
|
||
bit = cw[i] # 根据索引获取水印信息的当前位
|
||
if bit == '1':
|
||
original_amplitude = f_amplitudes[x[i], y[i]]
|
||
f_amplitudes[x[i], y[i]] = max_amplitude * alpha
|
||
f_amplitudes[N - x[i], M - y[i]] = max_amplitude * alpha
|
||
modified_amplitude = f_amplitudes[x[i], y[i]] # alpha是定义的强度因子
|
||
# print(f"点 {i + 1}: x = {int(x[i])}, y = {int(y[i])}, 角度 = {angles[i]}, 幅度 = {amplitudes[i]}, 相位 = {phase[i]}")
|
||
# print(f"原始幅度:{original_amplitude}")
|
||
# 打印嵌入水印信息后幅度
|
||
# print(f"嵌入水印信息后幅度: {modified_amplitude}")
|
||
else:
|
||
modified_amplitude = f_amplitudes[x[i], y[i]]
|
||
# 重新构造复数值并更新频域数据
|
||
# f_shifted[x[i], y[i]] = modified_amplitude * np.exp(1j * phase[i])
|
||
f_shifted = f_amplitudes * np.exp(1j * f_phase)
|
||
# 频域图像转换回空间域
|
||
img_lowpass_multi_circular = np.real(ifft2(ifftshift(f_shifted)))
|
||
b_channel = np.clip(img_lowpass_multi_circular, 0, 255).astype(np.uint16)
|
||
# 合并修改后的通道回到一个新的图像数组中
|
||
# merged_img = np.stack((r_channel, g_channel, b_channel), axis=-1)
|
||
corrected_image[:, :, 2] = b_channel
|
||
final_image = Image.fromarray(corrected_image)
|
||
# 添加边框
|
||
final_image_copy = final_image.copy()
|
||
border_size = 30
|
||
# border_color = (73, 116, 165)
|
||
# 设置border_color 为rgb 白色
|
||
border_color = (255, 255, 255)
|
||
border = (border_size, border_size, border_size, border_size) # (左, 上, 右, 下)
|
||
img_with_border = ImageOps.expand(final_image_copy, border=border, fill=border_color)
|
||
# 将merged_img保存到文件,文件是为当前时间的字符串
|
||
filename = f"{datetime.now().strftime('%Y%m%d%H%M%S')}.tiff"
|
||
# cv2.imwrite(filename, merged_img)
|
||
img_with_border.save(filename, format='TIFF')
|
||
# 显示结果
|
||
plt.figure(figsize=(12, 12))
|
||
plt.subplot(221)
|
||
plt.title("Original Image")
|
||
plt.imshow(img_copy, cmap='gray')
|
||
plt.subplot(222)
|
||
plt.title("Frequency Spectrum")
|
||
plt.imshow(np.log1p(np.abs(f_shifted)), cmap='gray')
|
||
plt.subplot(223)
|
||
plt.title("Multi Circular Lowpass Filter (50 Points per Circle)")
|
||
plt.imshow(frequency_domain_image, cmap='gray')
|
||
plt.subplot(224)
|
||
plt.title("Filtered Image (Multi Circular Low Frequencies, 50 Points per Circle)")
|
||
plt.imshow(final_image)
|
||
plt.tight_layout()
|
||
plt.show()
|
||
return filename
|
||
|
||
|
||
def validate_qr(filename, watermark_sequence):
|
||
watermarks = [int(watermark_sequence[i:i + 2]) for i in range(0, len(watermark_sequence), 2)]
|
||
# 根据 key读取数据库圆形信息
|
||
key = json.dumps(watermarks)
|
||
circles = []
|
||
# 查询第一条数据
|
||
qr = qrcode_data.select().where(qrcode_data.c.key == key)
|
||
result = connection.execute(qr).first()
|
||
if result:
|
||
# 将json字符串转换为列表
|
||
circles = json.loads(result[1])
|
||
print(circles)
|
||
# 验证水印结果
|
||
result, img2 = process_image_b_component(filename, circles, watermarks)
|
||
print(result)
|
||
else:
|
||
print("未找到数据")
|
||
# psnr = calculate_psnr(img_copy, img2)
|
||
# print(f"PSNR: {psnr}")
|
||
# # PSNR > 40 dB:通常被认为是高质量图像
|
||
# # 30 dB < PSNR < 40 dB:图像质量是良好
|
||
# if psnr > 40:
|
||
# print("图像质量是高质量")
|
||
# elif 35 <= psnr < 40:
|
||
# print("图像质量是良好")
|
||
# else:
|
||
# print("图像质量是差")
|
||
|
||
# img_path = './temp/tmpb_1ffsve.png'
|
||
# exec_image_result(img_path)
|
||
|
||
img_path = "corrected_image.png"
|
||
qr = "9918314391322762"
|
||
validate_qr(img_path, qr)
|
||
|
||
# perspective_transform(img_path)
|
||
|