1006. 换个格式输出整数 (15)

本文介绍了一个简单的程序,该程序能够将不超过三位的正整数转换为一种特定的格式,使用字母B代表百位、S代表十位,并列出个位数字。通过具体的输入输出样例展示了如何实现这一转换。

让我们用字母B来表示“百”、字母S表示“十”,用“12…n”来表示个位数字n(<10),换个格式来输出任一个不超过3位的正整数。例如234应该被输出为BBSSS1234,因为它有2个“百”、3个“十”、以及个位的4。

输入格式:每个测试输入包含1个测试用例,给出正整数n(<1000)。

输出格式:每个测试用例的输出占一行,用规定的格式输出n。

输入样例1:
234
输出样例1:
BBSSS1234
输入样例2:
23
输出样例2:
SS123

n = raw_input()
out = [0, 0, 0]
s = ''
for i in range(-len(n), 0):
    out[i] = int(n[i])
for i in range(0, out[0]):
    s = s + 'B'
for i in range(0, out[1]):
    s = s + 'S'
for i in range(1, out[2] + 1):
    s = s + str(i)
print s
import cv2 import sympy import numpy as np import easygui as g import time import argparse from tkinter import Tk, simpledialog from tkinter import filedialog, messagebox import tkinter as tk import numpy from numpy import * from scipy.optimize import minimize, root_scalar import os from scipy.optimize import curve_fit import matplotlib.pyplot as plt import pandas as pd from scipy.interpolate import interp1d from skimage import color from scipy.optimize import least_squares from scipy.optimize import minimize from colormath.color_conversions import convert_color from colormath.color_objects import sRGBColor, LabColor from scipy.spatial import distance from pyswarm import pso from pyswarms.single import GlobalBestPSO import pyswarms as ps from colormath.color_diff import delta_e_cie1976 from scipy.spatial.distance import euclidean from scipy.interpolate import RegularGridInterpolator # # 全局变量 start_point = (0, 0) end_point = (0, 0) selecting = False def load_array_from_file(file_path): try: array = np.loadtxt(file_path) return array except FileNotFoundError: messagebox.showerror("错误", f"文件 '{file_path}' 未找到。") except Exception as e: messagebox.showerror("错误", f"读取文件时发生错误 - {e}") def load_file(): global Lab_ideal_array file_path = filedialog.askopenfilename(title="选择文件", filetypes=[("Text files", "*.txt")]) if file_path: Lab_ideal_array = load_array_from_file(file_path) if Lab_ideal_array is not None: messagebox.showinfo("成功", f"文件加载成功,数组内容如下:\n{Lab_ideal_array}") root.quit() print('lab=', Lab_ideal_array) return Lab_ideal_array def open_file(): file_path = filedialog.askopenfilename() if file_path == "": os.path.get() #当打开文件路径选择框后点击"取消" 输入框会清空路径,所以使用get()方法再获取一次路径 else: path_ = file_path.replace("/", "\\") # 实际在代码中执行的路径为“\“ 所以替一下 os.path.set(path_) print(os.path.get()) def display_image(img): img_bgr = cv2.resize(img, (960, 540)) cv2.imshow('RGB Image', img_bgr) cv2.moveWindow('RGB Image', x=100, y=100) cv2.waitKey(0) cv2.destroyAllWindows() # 色块权重表配置 def save_numbers(entry_grid, numbers, root): numbers.clear() for i in range(4): for j in range(6): value = entry_grid[i][j].get() try: # 尝试将输入值转为浮点数 float_value = float(value) numbers.append(float_value) except ValueError: # 如果转失败,显示错误消息并返回 messagebox.showerror("输入错误", f"第 {i+1} 行, 第 {j+1} 列 的输入值 '{value}' 不是有效的数字。") return # 关闭窗口 root.quit() def create_input_grid(default_value=1): numbers = [] # 创建主窗口 root = tk.Tk() root.title("24色块权重表") # 创建色块权重的输入框 entry_grid = [] for i in range(4): row = [] for j in range(6): entry = tk.Entry(root, width=5) entry.insert(0, str(default_value)) entry.grid(row=i, column=j, padx=5, pady=5) row.append(entry) entry_grid.append(row) # 创建保存按钮 save_button = tk.Button( root, text="保存", command=lambda: save_numbers(entry_grid, numbers, root) # 传递必要的参数 ) save_button.grid(row=4, column=0, columnspan=6, pady=10) # 运行主循环 root.mainloop() return np.array(numbers) def degamma(img, block_size=512): print('max_img', np.max(img)) x = np.arange(0, 129) y = np.array( [0,77,110,136,158,178,197,214,231,246,261,276,290,303,316,329,342,354,366,378,389,400,411,422,433,443,453,463,473,483,493,502,511,521,530,539,547,556,564,573,581,589,597,605,613,620,628,635,643,650,657,664,671,678,685,691,698,704,711,717,723,730,736,742,748,753,759,765,770,776,782,787,792,798,803,808,813,818,823,828,833,838,843,847,852,857,861,866,870,875,879,883,888,892,896,900,905,909,913,917,921,925,929,933,937,941,944,948,952,956,959,963,967,970,974,978,981,985,988,992,995,999,1002,1006,1009,1013,1016,1020,1023]) # 填写实际数据 # 建立插值函数 f = interp1d(y, x, kind='linear', fill_value='extrapolate') height, width, channels = img.shape linear_img = np.empty_like(img, dtype=np.float32) # 数据量较大,分块处理 for ch in range(channels): for y_start in range(0, height, block_size): for x_start in range(0, width, block_size): y_end = min(y_start + block_size, height) x_end = min(x_start + block_size, width) block = img[y_start:y_end, x_start:x_end, ch] x_block = (block.astype(np.float32) / 256.0) * 1024.0 linear_block = f(x_block) linear_block = np.clip(linear_block, 0, 128) linear_uint8 = (linear_block / 128.0 * 256.0).astype(np.uint8) linear_img[y_start:y_end, x_start:x_end, ch] = linear_uint8 del block, x_block, linear_block, linear_uint8 return linear_img def gamma_brt(img, block_size = 512): x = np.arange(0, 129) y = np.array( [0,21,35,48,61,72,83,94,104,114,125,134,144,154,164,173,183,192,202,211,220,230,239,248,258,267,276,285,294,304,313,322,331,341,350,359,368,377,386,395,405,414,423,432,441,450,459,468,476,485,494,503,512,520,529,538,546,555,563,572,580,588,597,605,613,621,629,637,645,653,661,669,677,684,692,700,707,714,722,729,736,743,751,758,765,772,778,785,792,799,805,812,818,825,831,837,844,850,856,862,868,874,880,886,892,898,904,909,915,921,926,932,938,943,949,954,959,965,970,976,981,986,992,997,1002,1007,1013,1018,1023]) # 填写实际数据 # 建立插值函数 f = interp1d(x, y, kind='linear', fill_value='extrapolate') height, width, channels = img.shape srgb_img = np.empty_like(img, dtype=np.float32) #数据量较大,分块处理 for ch in range(channels): for y_start in range(0, height, block_size): for x_start in range(0, width, block_size): y_end = min(y_start + block_size, height) x_end = min(x_start + block_size, width) block = img[y_start:y_end, x_start:x_end, ch] x_block = (block.astype(np.float32) / 256.0) * 128.0 srgb_block = f(x_block) srgb_block = np.clip(srgb_block, 0, 1024) srgb_uint8 = (srgb_block / 1024.0 * 256.0).astype(np.uint8) srgb_img[y_start:y_end, x_start:x_end, ch] = srgb_uint8 del block, x_block, srgb_block, srgb_uint8 print('gamma_brt', np.max(srgb_img), np.min(srgb_img)) return srgb_img def gamma(img, block_size = 512): x = np.arange(0, 129) y = np.array( [0,55,102,135,165,189,212,232,251,267,283,299,314,327,341,354,367,378,390,401,412,422,433,443,453,462,471,480,488,497,506,514,523,530,538,546,554,561,569,576,584,591,598,605,612,619,626,633,640,646,652,658,665,671,677,683,689,695,701,707,713,718,724,730,736,741,746,751,757,762,767,772,777,782,787,793,798,803,808,812,817,822,827,832,837,842,846,851,856,860,865,870,874,879,883,888,893,897,901,906,910,915,919,923,928,932,936,940,944,949,953,957,961,965,969,973,977,981,985,989,993,996,1000,1004,1008,1011,1015,1019,1023]) # 填写实际数据 # 建立插值函数 f = interp1d(x, y, kind='linear', fill_value='extrapolate') height, width, channels = img.shape srgb_img = np.empty_like(img, dtype=np.float32) #数据量较大,分块处理 for ch in range(channels): for y_start in range(0, height, block_size): for x_start in range(0, width, block_size): y_end = min(y_start + block_size, height) x_end = min(x_start + block_size, width) block = img[y_start:y_end, x_start:x_end, ch] x_block = (block.astype(np.float32) / 256.0) * 128.0 srgb_block = f(x_block) srgb_block = np.clip(srgb_block, 0, 1024) srgb_uint8 = (srgb_block / 1024.0 * 256.0).astype(np.uint8) srgb_img[y_start:y_end, x_start:x_end, ch] = srgb_uint8 del block, x_block, srgb_block, srgb_uint8 return srgb_img def input_Lab_ideal(): # 初始化全局变量 global root # 创建主窗口 root = tk.Tk() root.title("选择文件读取数组") # 创建按钮 button_load = tk.Button(root, text="选择Lab标准", command=load_file) # 布局按钮 button_load.pack(pady=10) # 运行主循环 root.mainloop() root.destroy() return Lab_ideal_array # def mouse_callback(event, x, y, flags, param): global rectangles if event == cv2.EVENT_LBUTTONDOWN: # 记录起点 rectangles.append([x, y]) elif event == cv2.EVENT_LBUTTONUP: # 记录终点 rectangles[-1].extend([x, y]) # 在图像上画出矩形 cv2.rectangle(img_display, (rectangles[-1][0], rectangles[-1][1]), (rectangles[-1][2], rectangles[-1][3]), (0,255,0), 2) cv2.imshow('Image', img_display) def calculate_sub_rectangle_dimensions(W, H): # 计算新的小矩形宽度和高度(面积减半) sub_width = (W / 7.75) / np.sqrt(2) sub_height = (H / 5.25) / np.sqrt(2) spacing = (W - 6 * sub_width) / 7 return sub_width, sub_height, spacing # 鼠标回调函数 def mouse_callback(event, x, y, flags, param): global start_point, end_point, selecting if event == cv2.EVENT_LBUTTONDOWN: start_point = (x, y) end_point = (x, y) selecting = True elif event == cv2.EVENT_MOUSEMOVE: if selecting: end_point = (x, y) elif event == cv2.EVENT_LBUTTONUP: end_point = (x, y) selecting = False def draw_24color_RGB(img_bgr): # 保存原始图像尺寸 original_height, original_width = img_bgr.shape[:2] # 将图像调整为960x540 resized_img = cv2.resize(img_bgr, (960, 540), interpolation=cv2.INTER_AREA) clone_resized = resized_img.copy() cv2.namedWindow('image') cv2.setMouseCallback('image', mouse_callback) avg_rgb_values = [] while True: img_display = clone_resized.copy() if selecting: # 绘制大矩形 cv2.rectangle(img_display, start_point, end_point, (0, 255, 0), 2) # 计算小矩形的尺寸和位置,并绘制小矩形 x0, y0 = start_point x1, y1 = end_point width = abs(x1 - x0) height = abs(y1 - y0) x_min = min(x0, x1) y_min = min(y0, y1) sub_width, sub_height, spacing = calculate_sub_rectangle_dimensions(width, height) # 绘制小矩形 for i in range(4): for j in range(6): x = x_min + spacing + j * (sub_width + spacing) y = y_min + spacing + i * (sub_height + spacing) sub_x0 = int(x) sub_y0 = int(y) sub_x1 = int(x + sub_width) sub_y1 = int(y + sub_height) cv2.rectangle(img_display, (sub_x0, sub_y0), (sub_x1, sub_y1), (255, 0, 0), 1) cv2.imshow('image', img_display) key = cv2.waitKey(1) & 0xFF if key == 13: # Enter键 # 确认选择,计算小矩形的坐标和平均RGB值 x0, y0 = start_point x1, y1 = end_point width = abs(x1 - x0) height = abs(y1 - y0) x_min = min(x0, x1) y_min = min(y0, y1) sub_width, sub_height, spacing = calculate_sub_rectangle_dimensions(width, height) # 计算并输出每个小矩形的平均RGB值 for i in range(4): for j in range(6): x = x_min + spacing + j * (sub_width + spacing) y = y_min + spacing + i * (sub_height + spacing) sub_x0 = int(x) sub_y0 = int(y) sub_x1 = int(x + sub_width) sub_y1 = int(y + sub_height) # 将小矩形的坐标映射回原始图像尺寸 original_sub_x0 = int(sub_x0 * original_width / 960) original_sub_y0 = int(sub_y0 * original_height / 540) original_sub_x1 = int(sub_x1 * original_width / 960) original_sub_y1 = int(sub_y1 * original_height / 540) # 提取小矩形区域 roi = img_bgr[original_sub_y0:original_sub_y1, original_sub_x0:original_sub_x1] # 计算平均RGB值 avg_b = np.mean(roi[:, :, 0]) avg_g = np.mean(roi[:, :, 1]) avg_r = np.mean(roi[:, :, 2]) avg_rgb_values.append((avg_r, avg_g, avg_b)) # 打印每个色色块的平均RGB # print(f"Index ({i},{j}) Average RGB: ({avg_r}, {avg_g}, {avg_b})") # 绘制小矩形的边框在调整后的图像上 cv2.rectangle(clone_resized, (sub_x0, sub_y0), (sub_x1, sub_y1), (255, 0, 0), 1) # 绘制大矩形在调整后的图像上 cv2.rectangle(clone_resized, start_point, end_point, (0, 255, 0), 2) break elif key == 27: # Esc键 break del img_display # 显示已经完成框选的图片 cv2.imshow('Result', clone_resized) cv2.waitKey(0) cv2.destroyAllWindows() return avg_rgb_values def rgb2lab(rgb): # 将RGB值从0-255归一化到0-1 rgb_normalized = rgb / 255.0 # 创建sRGBColor对象 rgb_color = sRGBColor(rgb_normalized[0], rgb_normalized[1], rgb_normalized[2]) # 转到Lab颜色空间 lab = convert_color(rgb_color, LabColor) # 确保Lab值在范围内 lab_l = np.clip(lab.lab_l, 0, 100) lab_a = np.clip(lab.lab_a, -128, 127) lab_b = np.clip(lab.lab_b, -128, 127) # 返回ndarray return np.array([lab_l, lab_a, lab_b]) def deltaE(lab1, lab2): # 计算色差 return distance.euclidean(lab1, lab2) def normalize_ccm(ccm): # 将CCM每行和归一化为1 for row in range(3): row_sum = np.sum(ccm[row, :]) if row_sum != 0: ccm[row, :] /= row_sum return ccm def objective_function(ccm, rgb, std_lab, weights): # ccm是群体的位置, shape=(n_particles, 9) n_particles = ccm.shape[0] costs = [] for i in range(n_particles): # 取出第i个粒子的ccm ccm_i = ccm[i, :].reshape(3, 3) # 约束条件,将CCM每行和归一化为1 ccm_i = normalize_ccm(ccm_i) # 计算校正后的rgb corrected_rgb = rgb[:18] @ ccm_i.T # 将corrected_rgb的值截断到0-255之间 corrected_rgb = np.clip(corrected_rgb, 0, 255) # 转到Lab lab = np.array([rgb2lab(corrected_rgb[j]) for j in range(18)]) # 计算前18个色块的deltaE # deltaEs = [deltaE(lab[j], std_lab[j]) for j in range(18)] deltaEs = [deltaE(lab[j], std_lab[j]) * weights[j] for j in range(18)] # print('deltaE = ', deltaEs) # # 计算平均deltaE # mean_deltaE = np.mean(deltaEs) # costs.append(mean_deltaE) # 取最大 deltaE 作为 误差cost max_deltaE = np.max(deltaEs) costs.append(max_deltaE) return np.array(costs) def generate_init_pos(n_particles): # 生成初始位置,范围为[-1, 1] # init_pos = np.random.uniform(-2, 2, size=(n_particles, 9)) init_color = np.array([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]) init_pos = np.tile(init_color, (n_particles, 1)) return init_pos def find_optimal_CCM(rgb, std_lab, weights, ccm_limit): # 确保输入在范围内 rgb = np.clip(rgb, 0, 255) std_lab = np.clip(std_lab, [0, -128, -128], [100, 127, 127]) # 定义PSO的边界 lb = np.full(9, -np.inf) ub = np.full(9, np.inf) # 生成初始位置 init_pos = generate_init_pos(n_particles=30) # 设置PSO的选项 options = {'c1': 1.2, 'c2': 1.2, 'w': 0.6} # 初始化PSO optimizer = ps.single.GlobalBestPSO( n_particles=30, dimensions=9, options=options, bounds=(lb, ub), init_pos=init_pos ) # 运行优化 cost, pos = optimizer.optimize( objective_function, iters=300, rgb=rgb, std_lab=std_lab, weights=weights ) # reshape pos成3x3矩阵 ccm = pos.reshape(3, 3) # 将CCM每行和归一化为1 ccm = normalize_ccm(ccm) # 添加CCM矩阵对角线约束 diagonal_elements = np.diag(ccm) if np.any(diagonal_elements > ccm_limit): raise ValueError("One or more diagonal elements of the CCM matrix exceed 3. Process terminated.") # 使用最优 CCM 计算每个色块的色差 corrected_rgb = rgb[:18] @ ccm.T corrected_rgb = np.clip(corrected_rgb, 0, 255).astype(uint8) lab = np.array([rgb2lab(corrected_rgb[j]) for j in range(18)]) deltaEs = [deltaE(lab[j], std_lab[j]) for j in range(18)] # 计算打印每个色块的色差 print("DeltaE for each color patch with optimal CCM:") for j, deltaE_value in enumerate(deltaEs): print(f"Patch {j + 1}: {deltaE_value:.4f}") ccm = np.round(ccm * 255).astype(int) return ccm def objective(params, sectors, avg_yuv_list, yuv_ideal, weights): # def objective(params, sectors, avg_yuv_list, yuv_ideal): k = params[:24] theta_deg = params[24:48] theta_rad = np.deg2rad(theta_deg) error = 0.0 for i in range(18): # 只优化前18个色块 s = sectors[0, i] # 构建校正矩阵的转置 cos_theta = np.cos(theta_rad[s]) sin_theta = np.sin(theta_rad[s]) correction_matrix_T = np.array([ [1, 0, 0], [0, k[s] * cos_theta, k[s] * sin_theta], [0, -k[s] * sin_theta, k[s] * cos_theta] ]) # 应用校正矩阵 yuv_corrected = np.dot(avg_yuv_list[i], correction_matrix_T) # 计算误差 saturation_error = (yuv_corrected[1:] - yuv_ideal[i][1:]) ** 2 error += np.sum((yuv_corrected - yuv_ideal[i]) ** 2) + 2 * np.sum(saturation_error) # error += weights[i] * np.sum((yuv_corrected - yuv_ideal[i]) ** 2) # # error += np.sum((yuv_corrected - yuv_ideal[i]) ** 2) return error def calculate_correction_parameters(avg_rgb_list, Lab_ideal, weights): # def calculate_correction_parameters(avg_rgb_list, Lab_ideal): # if weights is None: # weights = np.ones(18) # 只优化前18个色块 # 确保输入是24x3的数组,输入均为float32 Lab_ideal = np.array(Lab_ideal, dtype=np.float32).reshape(24, 3) # 将avg_rgb_list从RGB转到HSV avg_rgb_uint8 = np.clip(avg_rgb_list, 0, 255).astype(np.uint8) # 将 RGB 转为 BGR(OpenCV 默认使用 BGR 格式) avg_rgb_uint8 = avg_rgb_uint8.reshape((1, 24, 3)) avg_bgr_uint8 = cv2.cvtColor(avg_rgb_uint8, cv2.COLOR_RGB2BGR) # 将 BGR 转为 HSV avg_hsv = cv2.cvtColor(avg_bgr_uint8, cv2.COLOR_BGR2HSV) # 将 H 的范围从 [0, 180] 转到 [0, 360],转为 float32 以便进行乘法操作 avg_hsv = avg_hsv.astype(np.float32) avg_hsv[:, :, 0] *= 2 print('avg_yuv_list_yuv2', avg_hsv[:, :, 0]) # 将H分成24个区间,每个15度 sectors = (avg_hsv[:, :, 0] / 15).astype(int) % 24 print("sectors:", sectors) # 将avg_rgb_list转到YUV avg_yuv_list = cv2.cvtColor(avg_rgb_uint8, cv2.COLOR_RGB2YUV).reshape((24, 3)) # print('avg_yuv_list_before', avg_yuv_list) # UV 减去 128 adjust_list_yuv = avg_yuv_list.copy() adjust_list_yuv = adjust_list_yuv.astype(np.int16) adjust_list_yuv[:, 1:] -= 128 # print('avg_yuv_list_after', adjust_list_yuv) Lab_ideal_copy = Lab_ideal.copy() Lab_ideal_reshape = Lab_ideal_copy.reshape(1, 24, 3) # 将 Lab 图像的值调整到 OpenCV 的期望范围 Lab_ideal_reshape[:, :, 0] = Lab_ideal_reshape[:, :, 0] * 255 / 100 Lab_ideal_reshape[:, :, 1:] = Lab_ideal_reshape[:, :, 1:] + 128 # 将浮点型转为 uint8 Lab_ideal_u8 = Lab_ideal_reshape.astype(np.uint8) # print('Lab_ideal', Lab_ideal_u8) # 使用 OpenCV 将 Lab 转为 BGR bgr_ideal = cv2.cvtColor(Lab_ideal_u8, cv2.COLOR_LAB2BGR) # 重塑回24个颜色块 # bgr_ideal = bgr_ideal.reshape(24, 3) # 转为YUV yuv_ideal = cv2.cvtColor(bgr_ideal, cv2.COLOR_BGR2YUV) yuv_ideal = np.clip(yuv_ideal, 0, 255).reshape(24, 3) adjust_ideal_yuv = yuv_ideal.copy() adjust_ideal_yuv = adjust_ideal_yuv.astype(np.int16) adjust_ideal_yuv[:, 1:] -= 128 # print('ideal_yuv_after', adjust_ideal_yuv) # 初始猜测值,k=1, theta=0 initial_guess = np.concatenate((np.ones(24), np.zeros(24))) # initial_guess[13] = 0.7 # 第13个蓝色的k值 # initial_guess[37] = -10 # 第13个蓝色的theta值 # 定义约束条件 bounds = [(0, 2) for _ in range(24)] + [(-60, 60) for _ in range(24)] # 提高计算精度 adjust_list_yuv_float = adjust_list_yuv.astype(np.float32) print('adjust_list_yuv_float = ', adjust_list_yuv_float) print('adjust_list_yuv_float[0] = ', adjust_list_yuv_float[0]) adjust_ideal_yuv_float = adjust_ideal_yuv.astype(np.float32) # 优化,传递sectors, avg_yuv_list, yuv_ideal作为额外参数 result = minimize( objective, initial_guess, args=(sectors, adjust_list_yuv_float, adjust_ideal_yuv_float, weights), # args=(sectors, adjust_list_yuv_float, adjust_ideal_yuv_float), bounds=bounds, method='L-BFGS-B', options={'maxiter': 10000, 'ftol': 1e-6} ) # result = minimize( # objective, # initial_guess, # args=(sectors, adjust_list_yuv_float, adjust_ideal_yuv_float, weights), # bounds=bounds, # method='trust-constr', # options={ # 'maxiter': 10000, # 'gtol': 1e-6, # 梯度容差 # 'xtol': 1e-8, # 参数变化容差 # } # ) # 提取优化后的k和theta k_opt = result.x[:24] theta_opt = result.x[24:48] # k_opt[13] -= 0.2 # k_opt[14] -= 0.1 # 计算H_map和S_map H_map = np.clip((theta_opt / 60.0 * 128 + 128), 0, 255).astype(np.int16) S_map = np.clip((128 * k_opt - 128), -128, 127).astype(np.int16) return np.vstack((k_opt, theta_opt)), np.vstack((H_map, S_map)) def apply_hsv_correction(img_corrected, k_theta_matrix, block_size=256): height, width, channels = img_corrected.shape img_final = np.empty((height, width, channels), dtype=np.uint8) # 将k_theta_matrix转置为24x2矩阵,并转为float32类型,shape: (24, 2) k_theta_matrix = k_theta_matrix.astype(np.float32).T for y_start in range(0, height, block_size): y_end = min(y_start + block_size, height) for x_start in range(0, width, block_size): x_end = min(x_start + block_size, width) # 提取块并转为HSV # block_rgb = img_corrected[y_start:y_end, x_start:x_end, :].astype(np.float32) block_rgb = img_corrected[y_start:y_end, x_start:x_end, :].astype(np.uint8) # print('block_rgb', block_rgb) block_hsv = cv2.cvtColor(block_rgb, cv2.COLOR_RGB2HSV) # print('block_hsv', block_hsv) # H = block_hsv[:, :, 0] H = np.clip(block_hsv[:, :, 0].astype(np.int32) * 2, 0, 360) # print('H = ', H) # 计算色块索引和插值系数 sector_idx = (H / 15).astype(np.int32) % 24 left_idx = (sector_idx - 1) % 24 right_idx = sector_idx alpha = (H % 15) / 15 # 线性插值 k 和 theta k = k_theta_matrix[left_idx, 0] * (1 - alpha) + k_theta_matrix[right_idx, 0] * alpha theta = k_theta_matrix[left_idx, 1] * (1 - alpha) + k_theta_matrix[right_idx, 1] * alpha # 计算cos和sin值 cos_theta = np.cos(np.deg2rad(theta)) sin_theta = np.sin(np.deg2rad(theta)) # 构建校正矩阵 # 校正矩阵的形状为 (height, width, 3, 3) correction_matrix = np.zeros((block_rgb.shape[0], block_rgb.shape[1], 3, 3), dtype=np.float32) correction_matrix[..., 0, 0] = 1 correction_matrix[..., 1, 1] = k * cos_theta correction_matrix[..., 1, 2] = -k * sin_theta correction_matrix[..., 2, 1] = k * sin_theta correction_matrix[..., 2, 2] = k * cos_theta # 将RGB转为YUV并应用校正 block_yuv = cv2.cvtColor(block_rgb, cv2.COLOR_RGB2YUV) adjust_block_yuv = block_yuv.astype(np.float32) adjust_block_yuv[..., 1] -= 128 adjust_block_yuv[..., 2] -= 128 block_yuv_corrected = np.matmul(correction_matrix, adjust_block_yuv[..., np.newaxis]).squeeze(axis=-1) yuv_corrected = block_yuv_corrected.copy() yuv_corrected[..., 1] += 128 yuv_corrected[..., 2] += 128 yuv_corrected = np.clip(yuv_corrected, 0, 255).astype(uint8) rgb_corrected = cv2.cvtColor(yuv_corrected, cv2.COLOR_YUV2RGB) img_final[y_start:y_end, x_start:x_end, :] = np.clip(rgb_corrected, 0, 255).astype(np.uint8) # # 将校正后的YUV转回RGB并存储结果 # block_rgb_corrected = cv2.cvtColor(block_yuv_corrected, cv2.COLOR_YUV2RGB) # img_final[y_start:y_end, x_start:x_end, :] = np.clip(block_rgb_corrected, 0, 255).astype(np.uint8) return img_final def read_raw(image_path, bit, w, h): if bit == 16: img = np.fromfile(image_path, dtype='uint16') img = img.reshape(h, w) elif bit == 12: with open(image_path, "rb") as rawimg: data = np.fromfile(rawimg, np.uint8, w * h * 3 // 2) data = data.astype(np.uint16) result = np.zeros(data.size * 2 // 3, np.uint16) result[0::2] = ((data[1::3] & 15) << 8) | data[0::3] result[1::2] = (data[1::3] >> 4) | (data[2::3] << 4) img = result.reshape(h, w) else: print('Error! raw_bit is Wrong, raw_bit should be 12 or 16') return None return img def correct_ob(img, bit, bl_level): img = img.astype(np.float32) img -= bl_level img = np.clip(img, 0, 2**bit - 1 - bl_level) # 归一化 img /= (2 ** bit - 1 - bl_level) img *= (2 ** bit - 1) img = np.clip(img, 0, 2 ** bit - 1).astype(np.uint16) return img def get_Rgain_Bgain(img_bgr): # 保存原始图像尺寸 original_height, original_width = img_bgr.shape[:2] # 将图像调整为960x540 resized_img = cv2.resize(img_bgr, (960, 540), interpolation=cv2.INTER_AREA) clone_resized = resized_img.copy() cv2.namedWindow('image') cv2.setMouseCallback('image', mouse_callback) # 初始化R、G、B的均值累加器 total_r = 0 total_g = 0 total_b = 0 while True: img_display = clone_resized.copy() if selecting: # 绘制大矩形 cv2.rectangle(img_display, start_point, end_point, (0, 255, 0), 2) # 计算大矩形的尺寸 x0, y0 = start_point x1, y1 = end_point width = abs(x1 - x0) height = abs(y1 - y0) x_min = min(x0, x1) y_min = min(y0, y1) # 计算小矩形的尺寸和间距 spacing_width = (width / 12) # 小矩形宽度的1/6 spacing_height = (height / 6) # 小矩形高度的1/6 sub_width = (width - 7 * spacing_width) / 6 # 6个小矩形 + 7个间距 sub_height = height - 2 * spacing_height # 上下各留一个间距 # 绘制6x1的框 for j in range(6): x = x_min + spacing_width + j * (sub_width + spacing_width) y = y_min + spacing_height sub_x0 = int(x) sub_y0 = int(y) sub_x1 = int(x + sub_width) sub_y1 = int(y + sub_height) cv2.rectangle(img_display, (sub_x0, sub_y0), (sub_x1, sub_y1), (255, 0, 0), 1) cv2.imshow('image', img_display) key = cv2.waitKey(1) & 0xFF if key == 13: # Enter键 # 确认选择,计算小矩形的坐标和R、G、B的均值 x0, y0 = start_point x1, y1 = end_point width = abs(x1 - x0) height = abs(y1 - y0) x_min = min(x0, x1) y_min = min(y0, y1) # 计算每个框的尺寸和间距 spacing_width = (width / 12) spacing_height = (height / 6) sub_width = (width - 7 * spacing_width) / 6 sub_height = height - 2 * spacing_height # 计算并累加每个小矩形的R、G、B的均值 for j in range(6): x = x_min + spacing_width + j * (sub_width + spacing_width) y = y_min + spacing_height sub_x0 = int(x) sub_y0 = int(y) sub_x1 = int(x + sub_width) sub_y1 = int(y + sub_height) # 将小矩形的坐标映射回原始图像尺寸 original_sub_x0 = int(sub_x0 * original_width / 960) original_sub_y0 = int(sub_y0 * original_height / 540) original_sub_x1 = int(sub_x1 * original_width / 960) original_sub_y1 = int(sub_y1 * original_height / 540) # 提取小矩形区域 roi = img_bgr[original_sub_y0:original_sub_y1, original_sub_x0:original_sub_x1] # 计算R、G、B的均值,并累加到总和中 total_r += np.mean(roi[:, :, 2]) # R通道的均值 total_g += np.mean(roi[:, :, 1]) # G通道的均值 total_b += np.mean(roi[:, :, 0]) # B通道的均值 # 绘制小矩形的边框在调整后的图像上 cv2.rectangle(clone_resized, (sub_x0, sub_y0), (sub_x1, sub_y1), (255, 0, 0), 1) # 绘制大矩形在调整后的图像上 cv2.rectangle(clone_resized, start_point, end_point, (0, 255, 0), 2) break elif key == 27: # Esc键 break del img_display # 显示960x540大小的已经完成框选的图片 cv2.imshow('Result', clone_resized) cv2.waitKey(0) cv2.destroyAllWindows() # 计算灰阶色块的R、G、B均值 avg_r = total_r / 6 avg_g = total_g / 6 avg_b = total_b / 6 # 计算WB gain RG = avg_g / avg_r BG = avg_g / avg_b return RG, BG def correct_white_balance(img, pattern, bit, RG, BG): img = img.astype(np.float32) if pattern.lower() == 'rggb': # 偶数行偶数列乘以BG img[::2, ::2] *= BG # 奇数行奇数列乘以RG img[1::2, 1::2] *= RG elif pattern.lower() == 'bggr': # 偶数行偶数列乘以RG img[::2, ::2] *= RG # 奇数行奇数列乘以BG img[1::2, 1::2] *= BG elif pattern.lower() == 'grbg': # 偶数行奇数列乘以RG img[::2, 1::2] *= RG # 奇数行偶数列乘以BG img[1::2, ::2] *= BG elif pattern.lower() == 'gbrg': # 偶数行奇数列乘以BG img[::2, 1::2] *= BG # 奇数行偶数列乘以RG img[1::2, ::2] *= RG else: print('Unsupported pattern:', pattern) return None # 确保数据不会超限 img = np.clip(img, 0, 2 ** bit - 1).astype(np.uint16) return img def demosaic(img, pattern): # 确定bayer模式标志 if pattern.lower() == 'bggr': bayer_flag = cv2.COLOR_BAYER_BG2BGR elif pattern.lower() == 'rggb': bayer_flag = cv2.COLOR_BAYER_RG2BGR elif pattern.lower() == 'grbg': bayer_flag = cv2.COLOR_BAYER_GR2BGR elif pattern.lower() == 'gbrg': bayer_flag = cv2.COLOR_BAYER_GB2BGR else: print('Unsupported pattern:', pattern) return # 检查图像是否正确读取 if img is None: raise ValueError("无法读取图像,请检查路径和格式。") img_bgr = cv2.cvtColor(img, bayer_flag) img_bgr = (img_bgr / 16).astype(np.uint8) return img_bgr def GammatoCCM(img_bgr, Lab_ideal_input, weights, ccm_limit): if weights is None: weights = np.ones(18) # 只优化前18个色块 # 获取24色块色块平均RGB值 avg_rgb_list = draw_24color_RGB(img_bgr) # 确保 avg_rgb_list 是NumPy数组 avg_rgb_list = np.array(avg_rgb_list, dtype=np.float32) # 对24色块的RGB值进行Gamma校正 avg_rgb_list_gamma = gamma(avg_rgb_list.reshape(24, 1, 3)).reshape(24, 3) target_lab_list = np.array(Lab_ideal_input, dtype=np.float32) # 寻找最优的CCM矩阵 best_CCM = find_optimal_CCM(avg_rgb_list_gamma, target_lab_list, weights, ccm_limit) best_CCM = np.round(best_CCM).astype(int) print("最优的CCM矩阵:", best_CCM) # 对24色块进行操作 # 使用 cv2.transform 进行CCM转 avg_rgb_list_gamma_reshaped = avg_rgb_list_gamma.reshape(24, 1, 3) # 进行CCM转 corrected_list_rgb = cv2.transform(avg_rgb_list_gamma_reshaped, best_CCM) corrected_list_rgb /= 255 # 将结果转(24, 3) 的形状 corrected_list_rgb = corrected_list_rgb.reshape(24, 3) corrected_rgb_list_uint8 = np.clip(corrected_list_rgb, 0, 255).astype(np.uint8) # 打印转后的RGB值 # print("转后的RGB值:", corrected_rgb_list_uint8) # 对图像进行Gamma校正 img_gamma_bgr = gamma(img_bgr) # 应用最优的CCM矩阵进行颜色校正 img_gamma_rgb = cv2.cvtColor(img_gamma_bgr, cv2.COLOR_BGR2RGB).astype(np.float32) img_corrected_float = cv2.transform(img_gamma_rgb, best_CCM) img_corrected_float /= 255 img_corrected_float = img_corrected_float.astype(np.float16) img_corrected = np.clip(img_corrected_float, 0, 255).astype(np.uint8) return img_corrected, corrected_list_rgb def CCMtoGamma(img_bgr, Lab_ideal_input, weights, ccm_limit): if weights is None: weights = np.ones(18) # 只优化前18个色块 # 将Lab值转为OpenCV所需的格式,L in [0, 255],a and b in [0, 255] Lab_ideal = Lab_ideal_input Lab_ideal[:, 0] = Lab_ideal_input[:, 0] * 255 / 100 Lab_ideal[:, 1:] = Lab_ideal[:, 1:] + 128 # AI提亮 # img_bgr = gamma_brt(img_bgr) # img_bgr = np.clip(img_bgr, 0, 255).astype(np.uint8) # 将Lab图像转为RGB图像 Lab_ideal = Lab_ideal.reshape(24, 1, 3).astype(np.uint8) rgb_ideal = cv2.cvtColor(Lab_ideal, cv2.COLOR_LAB2RGB) # degamma后转回Lab rgb_ideal_degamma = degamma(rgb_ideal) rgb_ideal_degamma /= 255.0 lab_ideal_degamma = cv2.cvtColor(rgb_ideal_degamma, cv2.COLOR_RGB2Lab) target_lab_list_degamma = np.array(lab_ideal_degamma, dtype=np.float32).reshape(24, 3) # 获取24色块色块平均RGB值 avg_rgb_list = draw_24color_RGB(img_bgr) # 确保 avg_rgb_list 是NumPy数组 avg_rgb_list = np.array(avg_rgb_list, dtype=np.float32) # 寻找最优的CCM矩阵 best_CCM = find_optimal_CCM(avg_rgb_list, target_lab_list_degamma, weights, ccm_limit) best_CCM = np.round(best_CCM).astype(int) print("最优的CCM矩阵:", best_CCM) # 对24色块进行操作 # 使用 cv2.transform 进行CCM转 # cv2.transform 需要输入数据的形状为 (N, 1, 3),其中 N 是样本数 avg_rgb_list_reshaped = avg_rgb_list.reshape(24, 1, 3) # 进行CCM转 # print("转前的RGB值:", avg_rgb_list_reshaped) avg_list_rgb = cv2.transform(avg_rgb_list_reshaped, best_CCM) avg_list_rgb /= 255 corrected_list_rgb = np.clip(avg_list_rgb, 0, 255) # print("转后的RGB值:", corrected_list_rgb) # gamma处理 corrected_list_rgb = gamma(corrected_list_rgb.reshape(24, 1, 3)).reshape(24, 3) corrected_list_rgb = np.clip(corrected_list_rgb, 0, 255).astype(np.float32) # 应用最优的CCM矩阵进行颜色校正 img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB).astype(np.float32) img_corrected_float = cv2.transform(img_rgb, best_CCM) img_corrected_float /= 255 img_corrected_float = np.clip(img_corrected_float, 0, 255).astype(np.float16) # img_corrected_float = img_corrected_float.astype(np.float32) # 对图像进行Gamma校正 img_gamma = gamma(img_corrected_float) img_corrected = np.clip(img_gamma, 0, 255).astype(np.uint8) return img_corrected, corrected_list_rgb # # def main_raw(image_path, pattern, w, h, bit, bl_level, RG, BG, correct_order): def main_raw(image_path, pattern, w, h, bit, bl_level, correct_order, ccm_limit): # 读取 RAW 图 img = read_raw(image_path, bit, w, h) if img is None: return None # OB img = correct_ob(img, bit, bl_level) # 获取wb gain img_wb = demosaic(img, pattern) RG, BG = get_Rgain_Bgain(img_wb) print('wb_gain', RG, BG) # 校正白平衡 img = correct_white_balance(img, pattern, bit, RG, BG) # demosaic img_bgr = demosaic(img, pattern) # 输入标准Lab Lab_ideal_input = input_Lab_ideal() Lab_ideal = Lab_ideal_input.copy() # 配置不同色块权重 weights = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) # weights = create_input_grid(default_value=1) # print('权重分布', weights) # 显示校正前的图像 # img_before_CCM = gamma(img_bgr) # img_before_CCM = np.clip(img_before_CCM, 0, 255).astype(np.uint8) # display_image(img_before_CCM) # 选择先进行gamma还是CCM # CCM & gamma if correct_order == 1: img_corrected, corrected_list_rgb = GammatoCCM(img_bgr, Lab_ideal_input, weights, ccm_limit) elif correct_order == 2: img_corrected, corrected_list_rgb = CCMtoGamma(img_bgr, Lab_ideal_input, weights, ccm_limit) else: raise ValueError("Invalid order. Choose 1 or 2.") # 显示CCM校正后的图像 img_corrected_bgr = cv2.cvtColor(img_corrected, cv2.COLOR_RGB2BGR) display_image(img_corrected_bgr) # HSV k_theta_matrix, H_S_matrix = calculate_correction_parameters(corrected_list_rgb, Lab_ideal, weights) # k_theta_matrix, H_S_matrix = calculate_correction_parameters(corrected_list_rgb, Lab_ideal) k_theta_matrix = k_theta_matrix.astype(np.float32) print('k_theta_corrected', k_theta_matrix) print('H_S_corrected', H_S_matrix) # correct_matrices = np.load('correct_matrices.npy') img_final = apply_hsv_correction(img_corrected, k_theta_matrix) return img_final # def main_jpg(image_path, ccm_limit): # # 读取 JPEG 图像 # img_bgr = cv2.imread(image_path) # if img_bgr is None: # print("Failed to load image.") # return None # # # 将图像从BGR转为RGB # img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB) # # # 输入标准Lab # Lab_ideal_input = input_Lab_ideal() # Lab_ideal = Lab_ideal_input.copy() # # # 配置不同色块权重 # weights = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) # # # 选择先进行gamma还是CCM # # CCM & gamma # img_corrected, corrected_list_rgb = CCMtoGamma(img_rgb, Lab_ideal_input, weights, ccm_limit) # # # 显示CCM校正后的图像 # img_corrected_bgr = cv2.cvtColor(img_corrected, cv2.COLOR_RGB2BGR) # display_image(img_corrected_bgr) # # # HSV # k_theta_matrix, H_S_matrix = calculate_correction_parameters(corrected_list_rgb, Lab_ideal) # k_theta_matrix = k_theta_matrix.astype(np.float32) # print('k_theta_corrected', k_theta_matrix) # print('H_S_corrected', H_S_matrix) # # # 应用HSV校正 # img_final = apply_hsv_correction(img_corrected, k_theta_matrix) # # return img_final def get_raw_config(): # 弹出输入框获取raw图像相关设置 raw_config = g.multenterbox(msg='输入raw相关设置', title='CCM', fields=['raw_pattern', 'raw_size_w', 'raw_size_h', 'raw_bit', 'raw_black_level', 'gamma->CCM(1) OR CCM->gamma(2)', 'CCM矩阵约束'], values=['bggr', '3840', '2160', '12', '256', '1', '3.0']) raw_pattern, raw_size_w, raw_size_h, raw_bit, bl_level, correct_order, ccm_limit = ( raw_config[0], int(raw_config[1]), int(raw_config[2]), int(raw_config[3]), int(raw_config[4]), int(raw_config[5]), float(raw_config[6]) ) return raw_pattern, raw_size_w, raw_size_h, raw_bit, bl_level, correct_order, ccm_limit if __name__ == '__main__': # 选择raw图像文件 image_path = g.fileopenbox(msg='输入raw图', title='客观校正', default='image/rgb.raw') # 获取raw配置参数 raw_config = get_raw_config() # 处理raw图像 image = main_raw(image_path, *raw_config) img_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) # cv2.imwrite('Corrected Image', img_bgr) img_bgr = cv2.resize(img_bgr, (960, 540)) cv2.imshow('Final Image', img_bgr) cv2.moveWindow('Final Image', x=100, y=100) cv2.waitKey(0) cv2.destroyAllWindows() print('finish') 分析一下以上代码,详细一些,包括整体算法架构以及各函数
最新发布
08-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值