数字图像处理(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)

相关推荐
Damon小智8 分钟前
合合信息DocFlow产品解析与体验:人人可搭建的AI自动化单据处理工作流
图像处理·人工智能·深度学习·机器学习·ai·自动化·docflow
FakeOccupational2 小时前
fpga系列 HDL:verilog 常见错误与注意事项 quartus13 bug 初始失效 reg *** = 1;
fpga开发·bug
好评笔记9 小时前
AIGC视频生成模型:Stability AI的SVD(Stable Video Diffusion)模型
论文阅读·人工智能·深度学习·机器学习·计算机视觉·面试·aigc
zxfeng~10 小时前
AG32 FPGA 的 Block RAM 资源:M9K 使用
fpga开发·ag32
whik119411 小时前
FPGA 开发工作需求明确:关键要点与实践方法
fpga开发
冰万森12 小时前
【图像处理】——掩码
python·opencv·计算机视觉
Antonio91513 小时前
【opencv】第10章 角点检测
人工智能·opencv·计算机视觉
whik119414 小时前
FPGA开发中的团队协作:构建高效协同的关键路径
fpga开发
南棱笑笑生14 小时前
20250117在Ubuntu20.04.6下使用灵思FPGA的刷机工具efinity刷机
fpga开发
paradoxjun16 小时前
落地级分类模型训练框架搭建(1):resnet18/50和mobilenetv2在CIFAR10上测试结果
人工智能·深度学习·算法·计算机视觉·分类