数字图像处理(17):RGB与HSL互转

(1)HSL:H色相、S饱和度、L亮度,其中H与HSV中的H一致,但是S饱和度与HSV中的S有区别,HSL呈现出一个双圆锥体形状,白色在上顶点,黑色在下顶点,最大横切面的圆心呈现半程灰色。

(2)matlab实现:

% 清空工作区
clear;
clc;

% 设定文件路径
input_path = 'D:\FPGA\Image processing\9_rgb_hsl\matlab\1_1920x1080.bmp';
output_folder = 'D:\FPGA\Image processing\9_rgb_hsl\matlab\';
txt_path = [output_folder 'output.txt'];

% 读取BMP图片
input_img = imread(input_path);
[height, width, ~] = size(input_img);

% 确保图片尺寸正确
if height ~= 1080 || width ~= 1920
    error('图片尺寸必须是1920x1080');
end

% 将RGB转换为HSL
rgb_normalized = double(input_img) / 255;
hsl_img = zeros(size(rgb_normalized));

for i = 1:height
    for j = 1:width
        r = rgb_normalized(i,j,1);
        g = rgb_normalized(i,j,2);
        b = rgb_normalized(i,j,3);
        
        cmax = max([r g b]);
        cmin = min([r g b]);
        delta = cmax - cmin;
        
        % 计算L (Lightness)
        L = (cmax + cmin) / 2;
        
        % 计算S (Saturation)
        if delta == 0
            S = 0;
        else
            S = delta / (1 - abs(2*L - 1));
        end
        
        % 计算H (Hue)
        if delta == 0
            H = 0;
        else
            if cmax == r
                H = 60 * mod(((g-b)/delta), 6);
            elseif cmax == g
                H = 60 * (((b-r)/delta) + 2);
            else
                H = 60 * (((r-g)/delta) + 4);
            end
        end
        
        if H < 0
            H = H + 360;
        end
        
        % 将HSL归一化到0-255范围
        hsl_img(i,j,1) = round(H * 255/360);
        hsl_img(i,j,2) = round(S * 255);
        hsl_img(i,j,3) = round(L * 255);
    end
end

% 保存HSL数据到txt文件
fid = fopen(txt_path, 'w');
for i = 1:height
    for j = 1:width
        fprintf(fid, '%d %d %d\n', ...
            round(hsl_img(i,j,1)), ...
            round(hsl_img(i,j,2)), ...
            round(hsl_img(i,j,3)));
    end
end
fclose(fid);

% 从txt文件读取HSL数据
fid = fopen(txt_path, 'r');
hsl_restored = zeros(height, width, 3);
for i = 1:height
    for j = 1:width
        line = fgetl(fid);
        values = sscanf(line, '%d %d %d');
        hsl_restored(i,j,:) = values;
    end
end
fclose(fid);

% 将HSL转换回RGB
rgb_restored = zeros(size(hsl_restored));

for i = 1:height
    for j = 1:width
        H = hsl_restored(i,j,1) * 360/255;
        S = hsl_restored(i,j,2) / 255;
        L = hsl_restored(i,j,3) / 255;
        
        % HSL到RGB的转换
        function_C = (1 - abs(2*L - 1)) * S;
        function_H = H/60;
        function_X = function_C * (1 - abs(mod(function_H, 2) - 1));
        
        if function_H >= 0 && function_H < 1
            R1 = function_C; G1 = function_X; B1 = 0;
        elseif function_H >= 1 && function_H < 2
            R1 = function_X; G1 = function_C; B1 = 0;
        elseif function_H >= 2 && function_H < 3
            R1 = 0; G1 = function_C; B1 = function_X;
        elseif function_H >= 3 && function_H < 4
            R1 = 0; G1 = function_X; B1 = function_C;
        elseif function_H >= 4 && function_H < 5
            R1 = function_X; G1 = 0; B1 = function_C;
        else
            R1 = function_C; G1 = 0; B1 = function_X;
        end
        
        function_m = L - (function_C/2);
        
        rgb_restored(i,j,1) = round((R1 + function_m) * 255);
        rgb_restored(i,j,2) = round((G1 + function_m) * 255);
        rgb_restored(i,j,3) = round((B1 + function_m) * 255);
    end
end

% 确保值在0-255范围内
rgb_restored = uint8(max(0, min(255, rgb_restored)));

% 显示原图、HSL图像和还原图像
figure;
subplot(1,3,1); imshow(input_img); title('原图');
subplot(1,3,2); imshow(uint8(hsl_img)); title('HSL图像');
subplot(1,3,3); imshow(rgb_restored); title('还原图像');

% 保存图像
imwrite(input_img, [output_folder 'original.bmp']);
imwrite(uint8(hsl_img), [output_folder 'hsl.bmp']);
imwrite(rgb_restored, [output_folder 'restored.bmp']);

% 计算原图和还原图的PSNR
mse = mean((double(input_img(:)) - double(rgb_restored(:))).^2);
psnr = 10 * log10(255^2/mse);
fprintf('PSNR: %.2f dB\n', psnr);

% 显示处理完成信息
fprintf('所有文件已保存在: %s\n', output_folder);

(3)FPGA实现(RGB转HSL)

module RGB_HSL
(
    input   wire                clk         ,
    input   wire                reset       ,
    input   wire                valid_i     ,
    input   wire    [23:0]      rgb_data_i  ,
                
    output  wire                valid_o     ,
    output  wire    [7:0]       H           ,
    output  wire    [7:0]       S           ,
    output  wire    [7:0]       L
);

// 第一级流水线 - 提取RGB分量并计算最大最小值
reg     [7:0]   r_reg, g_reg, b_reg;
reg     [8:0]   max_val, min_val;   // 增加1位防止溢出
reg     [1:0]   max_index;          // 记录最大值的颜色索引
reg             valid_p1;

// 第二级流水线 - 计算L和色差
reg     [8:0]   luminance;          // L = (max + min)/2
reg     [8:0]   delta;              // max - min
reg     [1:0]   max_index_p2;
reg             valid_p2;
reg     [8:0]   max_val_p2;
reg     [8:0]   min_val_p2;

// 第三级流水线 - H计算准备
reg     [19:0]  h_temp;             // 放大255倍的H值
reg     [19:0]  s_temp;             // 放大255倍的S值
reg             valid_p3;
reg     [8:0]   luminance_p3;

// 第四级流水线 - 最终计算
reg     [7:0]   h_final;
reg     [7:0]   s_final;
reg     [7:0]   l_final;
reg             valid_p4;

// 输入RGB提取
wire    [7:0]   red   = rgb_data_i[23:16];
wire    [7:0]   green = rgb_data_i[15:8];
wire    [7:0]   blue  = rgb_data_i[7:0];

// 第一级流水线逻辑
always @(posedge clk or posedge reset) begin
    if (reset) begin
        r_reg <= 8'd0;
        g_reg <= 8'd0;
        b_reg <= 8'd0;
        max_val <= 9'd0;
        min_val <= 9'd0;
        max_index <= 2'd0;
        valid_p1 <= 1'b0;
    end
    else if (valid_i) begin
        r_reg <= red;
        g_reg <= green;
        b_reg <= blue;
        valid_p1 <= valid_i;
        
        // 计算最大值和最小值
        if (red >= green && red >= blue) begin
            max_val <= {1'b0, red};
            max_index <= 2'd0;
        end
        else if (green >= red && green >= blue) begin
            max_val <= {1'b0, green};
            max_index <= 2'd1;
        end
        else begin
            max_val <= {1'b0, blue};
            max_index <= 2'd2;
        end
        
        if (red <= green && red <= blue)
            min_val <= {1'b0, red};
        else if (green <= red && green <= blue)
            min_val <= {1'b0, green};
        else
            min_val <= {1'b0, blue};
    end
    else
        valid_p1 <= 1'b0;
end

// 第二级流水线逻辑
always @(posedge clk or posedge reset) begin
    if (reset) begin
        luminance <= 9'd0;
        delta <= 9'd0;
        max_index_p2 <= 2'd0;
        valid_p2 <= 1'b0;
        max_val_p2 <= 9'd0;
        min_val_p2 <= 9'd0;
    end
    else if (valid_p1) begin
        // 计算亮度 L = (max + min)/2
        luminance <= (max_val + min_val) >> 1;
        delta <= max_val - min_val;
        max_index_p2 <= max_index;
        valid_p2 <= valid_p1;
        max_val_p2 <= max_val;
        min_val_p2 <= min_val;
    end
    else
        valid_p2 <= 1'b0;
end

// 第三级流水线逻辑
always @(posedge clk or posedge reset) begin
    if (reset) begin
        h_temp <= 20'd0;
        s_temp <= 20'd0;
        valid_p3 <= 1'b0;
        luminance_p3 <= 9'd0;
    end
    else if (valid_p2) begin
        valid_p3 <= valid_p2;
        luminance_p3 <= luminance;
        
        // 先计算0-360度范围的H值,然后乘以255/360转换到0-255范围
        if (delta == 9'd0)
            h_temp <= 20'd0;
        else begin
            case (max_index_p2)
                2'd0: begin  // max = red
                    if (g_reg >= b_reg)
                        h_temp <= (((g_reg - b_reg) * 20'd60) / delta * 20'd255) / 20'd360;
                    else
                        h_temp <= ((((g_reg - b_reg) * 20'd60) / delta + 20'd360) * 20'd255) / 20'd360;
                end
                2'd1: begin  // max = green
                    h_temp <= ((((b_reg - r_reg) * 20'd60) / delta + 20'd120) * 20'd255) / 20'd360;
                end
                2'd2: begin  // max = blue
                    h_temp <= ((((r_reg - g_reg) * 20'd60) / delta + 20'd240) * 20'd255) / 20'd360;
                end
                default: h_temp <= 20'd0;
            endcase
        end
        
        // 计算饱和度 S (保持不变)
        if (luminance == 9'd0 || luminance == 9'd255 || delta == 9'd0)
            s_temp <= 20'd0;
        else if (luminance <= 9'd127)
            s_temp <= (delta * 20'd255) / (max_val_p2 + min_val_p2);
        else
            s_temp <= (delta * 20'd255) / (9'd510 - max_val_p2 - min_val_p2);
    end
    else
        valid_p3 <= 1'b0;
end

// 第四级流水线逻辑 - 最终输出
always @(posedge clk or posedge reset) begin
    if (reset) begin
        h_final <= 8'd0;
        s_final <= 8'd0;
        l_final <= 8'd0;
        valid_p4 <= 1'b0;
    end
    else if (valid_p3) begin
        // 规范化H值到0-255
        h_final <= (h_temp[19] ? (h_temp + 20'd255) : h_temp);
        // 规范化S值到0-255
        s_final <= s_temp[7:0];
        // 规范化L值到0-255
        l_final <= luminance_p3[7:0];
        valid_p4 <= valid_p3;
    end
    else
        valid_p4 <= 1'b0;
end

// 输出赋值
assign H = h_final;
assign S = s_final;
assign L = l_final;
assign valid_o = valid_p4;

endmodule

FPGA实现(HSL转RGB)

相关推荐
goomind1 小时前
YOLOv8实战bdd100k自动驾驶目标识别
人工智能·深度学习·yolo·计算机视觉·目标跟踪·自动驾驶·bdd100k
博雅智信1 小时前
人工智能-自动驾驶领域
人工智能·python·深度学习·yolo·机器学习·计算机视觉·自动驾驶
人工智能培训网3 小时前
《计算机视觉证书:开启职业发展新航道》
人工智能·计算机视觉
想成为风筝3 小时前
HALCON算子函数 Filter(过滤)(1)
图像处理·深度学习
肉包之4 小时前
pythonOpenCV篇:0基础带你python入门之常用函数
人工智能·python·opencv·计算机视觉·目标跟踪
胡说八道的Dr. Zhu5 小时前
【图像去雾数据集】URHI数据集介绍
人工智能·计算机视觉
技术小白爱FPGA5 小时前
Xilinx IDDR和 ODDR原语使用和仿真
fpga开发
CUGLin5 小时前
遥感图像处理二(ENVI5.6 Classic)
图像处理·人工智能·计算机视觉
技术小白爱FPGA6 小时前
Xilinx LVDS 接口中的时钟对齐模块的RTL编写
fpga开发
Anin蓝天(北京太速科技-陈)6 小时前
204-基于Xilinx Virtex-6 XC6VLX240T 和TI DSP TMS320C6678的信号处理板
嵌入式硬件·fpga开发·信号处理