f.lux for Linux安装

本文详细介绍了如何通过命令行工具安装f.lux,并指导用户如何调整程序设置以适应不同地理位置,确保在夜间使用电脑时减少蓝光影响,提升视觉舒适度。同时,提供替换系统中默认的xflux程序的方法,确保兼容性和性能优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.安装f.lux
sudo add-apt-repository ppa:kilian/f.lux sudo apt-get update sudo apt-get install fluxgui

2.去官网下载核心程序xflux来替换/usr/bin目录下同名的程序。
64位:https://justgetflux.com/linux/xflux64.tgz
32位:https://justgetflux.com/linux/xflux-pre.tgz

3.打开f.lux,在preference设置经纬度,程序随系统启动。

转载于:https://www.cnblogs.com/LicwStack/p/4907272.html

修改这段代码以支持打包 import os import cv2 import numpy as np import screeninfo from PIL import Image, ImageDraw, ImageFont import time from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler import os import logging # 配置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S') def resource_path(relative_path): """获取资源绝对路径,支持PyInstaller打包后运行""" try: base_path = sys._MEIPASS except Exception: base_path = os.path.abspath(".") return os.path.join(base_path, relative_path) class EnhancedImageViewer: """增强版图像查看器,支持亮度查看(Lux值)""" def __init__(self, image_path, title="图像查看器", base_output_name=None): self.image_path = image_path self.original_image = cv2.imread(image_path) if self.original_image is None: raise FileNotFoundError(f"无法加载图像: {image_path}") # 保存基础输出名称 self.base_output_name = base_output_name if base_output_name else \ os.path.splitext(os.path.basename(image_path))[0] # 获取灰度图像用于亮度分析 self.gray_image = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) # 获取屏幕尺寸 try: screen = screeninfo.get_monitors()[0] self.max_width = screen.width - 100 self.max_height = screen.height - 100 except: self.max_width = 1620 self.max_height = 880 # 初始缩放状态 self.scale_factor = 1.0 self.offset_x = 0 self.offset_y = 0 # 创建显示图像 self.display_image = self.original_image.copy() self.resized_display = self.resize_to_fit(self.original_image) # 创建窗口 self.window_name = title cv2.namedWindow(self.window_name, cv2.WINDOW_NORMAL) cv2.setMouseCallback(self.window_name, self.mouse_callback) # 更新显示 self.update_display() def resize_to_fit(self, image): """调整图像尺寸以适应屏幕""" height, width = image.shape[:2] scale_width = self.max_width / width scale_height = self.max_height / height self.scale_factor = min(scale_width, scale_height, 1.0) new_width = int(width * self.scale_factor) new_height = int(height * self.scale_factor) if self.scale_factor < 1.0: return cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_AREA) return image.copy() def put_chinese_text(self, image, text, position, font_size=20, color=(255, 255, 255)): """在图像上添加中文文本""" if image is None or image.size == 0: return image # 确保图像是3通道的 if len(image.shape) == 2: image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR) # 转换为PIL图像 (RGB格式) pil_img = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) draw = ImageDraw.Draw(pil_img) # 使用支持中文的字体 try: font = ImageFont.truetype("simhei.ttf", font_size) except: try: font = ImageFont.truetype("msyh.ttc", font_size) except: try: font = ImageFont.truetype("/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf", font_size) except: font = ImageFont.load_default() # 添加文本 draw.text(position, text, font=font, fill=color) # 转换回OpenCV格式 return cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) def update_display(self): """更新显示图像""" # 缩放小于等于1.0时直接显示 self.display_image = self.resized_display.copy() # 添加帮助文本 help_text = "左键:查看亮度(Lux) | ESC:退出 | R:重置 | S:保存" self.display_image = self.put_chinese_text( self.display_image, help_text, (10, 20), font_size=20, color=(0, 255, 0) ) # 显示图像 cv2.imshow(self.window_name, self.display_image) def mouse_callback(self, event, x, y, flags, param): """鼠标事件回调函数 - 仅保留左键点击功能""" # 鼠标左键点击 - 显示亮度值(Lux) if event == cv2.EVENT_LBUTTONDOWN: # 计算原始图像坐标 orig_x, orig_y = self.convert_coords(x, y) # 获取原始图像中的灰度值 if 0 <= orig_x < self.gray_image.shape[1] and 0 <= orig_y < self.gray_image.shape[0]: gray_value = self.gray_image[orig_y, orig_x] # 将灰度值转换为Lux值 (0-255范围映射到0-740 Lux) lux_value = int((gray_value / 255.0) * 740) # 在当前显示图像上添加标记和信息 display_copy = self.display_image.copy() cv2.circle(display_copy, (x, y), 5, (0, 0, 255), -1) # 计算文本位置(避免遮挡) text_x = x + 10 text_y = y - 10 # 如果靠近右侧边缘,向左移动文本 if text_x > self.display_image.shape[1] - 250: text_x = x - 250 # 如果靠近底部边缘,向上移动文本 if text_y < 30: text_y = y + 20 # 添加中文文本(显示Lux值) text = f"位置: ({orig_x}, {orig_y}) 亮度: {lux_value} Lux" display_copy = self.put_chinese_text( display_copy, text, (text_x, text_y), font_size=18, color=(0, 255, 255) ) cv2.imshow(self.window_name, display_copy) def convert_coords(self, x, y): """将显示坐标转换为原始图像坐标""" # 缩小或正常状态下的坐标转换 orig_x = int(x / self.scale_factor) orig_y = int(y / self.scale_factor) # 确保坐标在有效范围内 orig_x = max(0, min(orig_x, self.original_image.shape[1] - 1)) orig_y = max(0, min(orig_y, self.original_image.shape[0] - 1)) return orig_x, orig_y def run(self): """运行查看器主循环""" while True: key = cv2.waitKey(1) & 0xFF if key == 27: # ESC退出 break elif key == ord('r'): # 重置视图 self.scale_factor = 1.0 self.offset_x = 0 self.offset_y = 0 self.resized_display = self.resize_to_fit(self.original_image) self.update_display() elif key == ord('s'): # 保存当前视图 # 使用基础输出名称生成截图文件名 screenshot_path = f"{self.base_output_name}_screenshot.png" cv2.imwrite(screenshot_path, self.display_image) print(f"截图已保存为 {screenshot_path}") cv2.destroyAllWindows() def preprocess_image(image_path): """图像预处理""" image = cv2.imread(image_path) if image is None: raise FileNotFoundError(f"无法加载图像: {image_path}") # 转换为灰度图并降噪 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (9, 9), 0) # 对比度增强 clahe = cv2.createCLAHE(clipLimit=4.0, tileGridSize=(8, 8)) enhanced = clahe.apply(blurred) return image, gray, enhanced def analyze_intensity(enhanced): """亮度分析""" min_intensity = np.min(enhanced) max_intensity = np.max(enhanced) normalized = cv2.normalize(enhanced.astype('float'), None, 0, 1, cv2.NORM_MINMAX) return min_intensity, max_intensity, normalized def generate_heatmap(image, normalized): """生成热力图""" heatmap = cv2.applyColorMap((normalized * 255).astype(np.uint8), cv2.COLORMAP_JET) blended = cv2.addWeighted(image, 0.7, heatmap, 0.3, 0) return heatmap, blended def process_contours(image, enhanced, min_intensity, max_intensity, num_levels=7): """处理等高线""" height, width = image.shape[:2] contour_image = np.zeros_like(image) color_intensity_map = [] # 计算亮度层级 levels = np.linspace(min_intensity, max_intensity, num_levels).astype(np.uint8) kernel = np.ones((3, 3), np.uint8) for i, level in enumerate(levels): # 创建当前亮度层级的掩膜 lower_val = max(int(level) - 10, 0) upper_val = min(int(level) + 10, 255) mask = cv2.inRange(enhanced, lower_val, upper_val) # 形态学处理 mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 查找等高线 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 计算颜色(冷色调到暖色调渐变) normalized_level = (level - min_intensity) / (max_intensity - min_intensity) if normalized_level < 0.5: hue = 120 + 60 * normalized_level * 2 else: hue = 60 * (1 - (normalized_level - 0.5) * 2) hue = np.clip(hue, 0, 180) # 转换为BGR颜色 color = cv2.cvtColor(np.uint8([[[hue, 255, 255]]]), cv2.COLOR_HSV2BGR)[0][0] color = tuple(map(int, color)) # 存储颜色-亮度映射 # 将灰度值转换为Lux值 (0-255范围映射到0-740 Lux) lux_value = int((level / 255.0) * 740) color_intensity_map.append((color, lux_value)) # 绘制等高线 cv2.drawContours(contour_image, contours, -1, color, 2) return contour_image, color_intensity_map def create_color_bar(image, color_intensity_map, min_intensity, max_intensity): """创建颜色条 - 显示Lux值""" height, width = image.shape[:2] bar_width = int(width * 0.03) bar_height = int(height * 0.3) bar_x = width - int(width * 0.05) - bar_width bar_y = int(height * 0.05) # 生成颜色条 color_bar = np.zeros((bar_height, bar_width, 3), dtype=np.uint8) for i in range(bar_height): idx = int((1 - i / bar_height) * (len(color_intensity_map) - 1)) color_bar[i, :] = color_intensity_map[idx][0] # 添加到图像 result = image.copy() result[bar_y:bar_y + bar_height, bar_x:bar_x + bar_width] = color_bar # 添加边框 cv2.rectangle(result, (bar_x, bar_y), (bar_x + bar_width, bar_y + bar_height), (255, 255, 255), 1) # 添加刻度和标签(显示Lux值) num_ticks = 5 min_lux = 0 max_lux = 740 for i, pos in enumerate(np.linspace(0, bar_height, num_ticks)): y_pos = int(bar_y + pos) cv2.line(result, (bar_x - 5, y_pos), (bar_x, y_pos), (255, 255, 255), 1) # 计算标签位置 value = int(min_lux + (max_lux - min_lux) * (1 - pos / bar_height)) text_x = bar_x - 50 text_y = y_pos + (15 if i == 0 else -10 if i == num_ticks - 1 else 0) # 添加带描边的文本 cv2.putText(result, f"{value} Lux", (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 2) cv2.putText(result, f"{value} Lux", (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1) # 添加标题 cv2.putText(result, 'Light Intensity (Lux)', (bar_x - 150, bar_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 0), 2) cv2.putText(result, 'Light Intensity (Lux)', (bar_x - 150, bar_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1) return result class ImageHandler(FileSystemEventHandler): def __init__(self, processing_function): self.processing_function = processing_function self.supported_exts = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff'] def on_created(self, event): """当新文件创建时触发""" if not event.is_directory: file_path = event.src_path if self._is_image(file_path): logging.info(f"检测到新图片: {file_path}") # 等待文件完全写入(根据实际需求调整) time.sleep(0.5) self.processing_function(file_path) def _is_image(self, file_path): """检查是否为支持的图片格式""" ext = os.path.splitext(file_path)[1].lower() return ext in self.supported_exts def start_monitoring(path_to_watch, processing_function): """启动文件夹监控服务""" event_handler = ImageHandler(processing_function) observer = Observer() observer.schedule(event_handler, path_to_watch, recursive=False) observer.start() logging.info(f"开始监控文件夹: {path_to_watch}") try: while True: time.sleep(1) except KeyboardInterrupt: observer.stop() observer.join() def main(image_path): """主处理流程""" try: # 从路径中提取基础文件名(不含扩展名) base_name = os.path.splitext(os.path.basename(image_path))[0] # 1. 图像预处理 image, gray, enhanced = preprocess_image(image_path) # 2. 亮度分析 min_intensity, max_intensity, normalized = analyze_intensity(enhanced) # 3. 生成热力图 heatmap, blended = generate_heatmap(image, normalized) # 4. 处理等高线 contour_image, color_intensity_map = process_contours( image, enhanced, min_intensity, max_intensity ) # 5. 创建最终结果(显示Lux值) base_image = cv2.addWeighted(image, 0.7, contour_image, 0.3, 0) # 使用固定的0-740 Lux范围 min_lux = 0 max_lux = 740 final_result = create_color_bar(base_image, color_intensity_map, min_lux, max_lux) # 保存结果(使用基础文件名作为前缀) cv2.imwrite(f"{base_name}_result.png", final_result) cv2.imwrite(f"{base_name}_Contours.png", contour_image) cv2.imwrite(f"{base_name}_Heatmap.png", heatmap) cv2.imwrite(f"{base_name}_Blended.png", blended) print(f"处理完成! 结果已保存为 {base_name}_*.png") # 启动交互式查看器(传递基础文件名) viewer = EnhancedImageViewer('4.jpg', 'photo_view', base_output_name=base_name) viewer.run() except Exception as e: print(f"处理过程中发生错误: {str(e)}") if __name__ == "__main__": # 修改这里的图片路径 image_path = '4.jpg' main(image_path)
最新发布
07-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值