问题 K: 【组合数学】Round Numbers

The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, Paper, Stone’ (also known as ‘Rock, Paper, Scissors’, ‘Ro, Sham, Bo’, and a host of other names) in order to make arbitrary decisions such as who gets to be milked first. They can’t even flip a coin because it’s so hard to toss using hooves.

They have thus resorted to “round number” matching. The first cow picks an integer less than two billion. The second cow does the same. If the numbers are both “round numbers”, the first cow wins,
otherwise the second cow wins.

A positive integer N is said to be a “round number” if the binary representation of N has as many or more zeroes than it has ones. For example, the integer 9, when written in binary form, is 1001. 1001 has two zeroes and two ones; thus, 9 is a round number. The integer 26 is 11010 in binary; since it has two zeroes and three ones, it is not a round number.

Obviously, it takes cows a while to convert numbers to binary, so the winner takes a while to determine. Bessie wants to cheat and thinks she can do that if she knows how many “round numbers” are in a given range.

Help her by writing a program that tells how many round numbers appear in the inclusive range given by the input (1 ≤ Start < Finish ≤ 2,000,000,000).

输入
Line 1: Two space-separated integers, respectively Start and Finish.

输出
Line 1: A single integer that is the count of round numbers in the inclusive range Start…Finish

样例输入
复制样例数据
2 12
样例输出
6

首先要相求[a , b]里面的个数,只需要用[0 , b + 1] - [0 , a] , 为何不是[0 , b] - [0 , a - 1]的原因是下面求的是[0 , k]里面小于k 的round numbers, ,然后将考虑求[0 , k] 里面的round numbers个数,首先将k转化为二进制存在一个数组里面 , 长度为b[0] , 因为题目说了, 最高位肯定为1, 所以我们先求一下长度为b[0] - 1的有多少种round numbers, 这个长度的我们只要满足0的个数大于1的个数的就是一个round numbers, 因为长度为len - 1 , 永远比k小, 永远符合条件, 所以

	for(int i = 1 ;i < b[0] - 1 ;i ++)
	 for(int j = i / 2 + 1 ;j <= i ;j ++)
	  sum += c[i][j] ;

借用一下数学一本通上面的图片
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

#include <iostream>
using namespace std;
int c[33][33] ;
int b[35] ;
void prepare()
{
	for(int i = 0 ;i <= 32 ;i ++)
	 for(int j = 0 ;j <= i ;j ++)
	  if(!j || i == j)
	   c[i][j] = 1 ;
	  else c[i][j] = c[i - 1][j] + c[i - 1][j - 1] ;
	return ; 
}
void solve(int n)
{
	b[0] = 0 ;
	while(n)
	 b[ ++ b[0]] = n % 2 , n /= 2 ;
	return ;
}
int calc(int n)
{
	solve(n) ;
	int sum = 0 ;
	for(int i = 1 ;i < b[0] - 1 ;i ++)
	 for(int j = i / 2 + 1 ;j <= i ;j ++)
	  sum += c[i][j] ;
	int zero = 0 ;
	for(int i = b[0] - 1 ; i >= 1 ;i --)
	 if(b[i])
	  for(int j = (b[0] + 1) / 2 - zero - 1 ;j <= i - 1 ;j ++)
	   sum += c[i - 1][j] ;
	 else zero ++ ;
	 return sum ;
}
int main()
{
	prepare() ;
	int a , b ; 
	cin >> a >> b ;
	cout << calc(b + 1) - calc(a) << endl ; 
	return 0 ;
}
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、付费专栏及课程。

余额充值