0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何在FPGA中实现RGB转HSV

FPGA开源工坊 来源:FPGA开源工坊 2023-07-02 11:49 次阅读

HSV色彩空间相对于RGB色彩空间更适合做颜色追踪,分割颜色等。那么RGB色彩空间要怎么转变为HSV色彩空间呢。

转换公式如下:

7a9fcc5a-1825-11ee-962d-dac502259ad0.png

需要注意的是在OpenCV中为了显示HSV色彩空间的内容会将H的值除以2,S的值和V的值是要乘以255。

FPGA中实现RGB转HSV的话,上面公式中第一步除以255的归一化是可以不做的。因为在H和S的计算中255可以约掉的,如下所示。而在V的值需要乘以255来显示,所以也可以不除以255.

7ad93fda-1825-11ee-962d-dac502259ad0.png

如R,G,B为169 152 133的值计算过程如下:

7af3848a-1825-11ee-962d-dac502259ad0.png

定义如下

7b0e3816-1825-11ee-962d-dac502259ad0.png

在计算中需要使用除法器:

7b30036a-1825-11ee-962d-dac502259ad0.png

因为8bit的整数,8bit小数的有符号数,所以数据位宽为17bit。

仿真结果如下:

7b462d48-1825-11ee-962d-dac502259ad0.png

可以看到ref和dut之间有误差,这个是因为计算过程中采用了8bit的定点小数造成的,如果小数位宽扩大,那么可以减少误差。

仿真用的计分板:

7b670a68-1825-11ee-962d-dac502259ad0.png

提供SpinalHDL的源码:如果需要Verilog源码可以私聊

import spinal.core._
import spinal.lib._


class Rgb2hsv extends Component {
    val io = new Bundle {
        val dataIn = slave(FrameInterface(24))
        val dataOut = master(FrameInterface(24))
    }


    val R, G, B = UInt(8 bits)
    val RMax = Reg(Bool()) init False
    val GMax = Reg(Bool()) init False
    val BMax = Reg(Bool()) init False
    val RMaxDelay = Delay(RMax, 12, init = False)
    val GMaxDelay = Delay(GMax, 12, init = False)
    val BMaxDelay = Delay(BMax, 12, init = False)
    val CMax = Reg(UInt(8 bits))
    val CMin = Reg(UInt(8 bits))
    val derta = UInt(8 bits)


    val calcH = new Area {
        val dertaEq0 = Delay(derta === 0, 12)
        val G_B = RegNext(((U"1'b0" @@ G).asSInt - (U"1'b0" @@ B).asSInt) @@ S"8'd0")
        val B_R = RegNext(((U"1'b0" @@ B).asSInt - (U"1'b0" @@ R).asSInt) @@ S"8'd0")
        val R_G = RegNext(((U"1'b0" @@ R).asSInt - (U"1'b0" @@ G).asSInt) @@ S"8'd0")
        val div1 = new Div(17, 8)
        val div2 = new Div(17, 8)
        val div3 = new Div(17, 8)
        val G_B_derta = Bits(17 bits)
        val B_R_derta = Bits(17 bits)
        val R_G_derta = Bits(17 bits)
        val G_B_derta_add = Reg(SInt(17 bits))
        val B_R_derta_add = Reg(SInt(17 bits))
        val R_G_derta_add = Reg(SInt(17 bits))
        val G_B_derta_add_mul = Reg(SInt(16 bits))
        val B_R_derta_add_mul = Reg(SInt(16 bits))
        val R_G_derta_add_mul = Reg(SInt(16 bits))
        val H_D = Reg(UInt(9 bits))
        val H = Reg(UInt(8 bits))
        div1.driverFrom(G_B.asBits, (U"1'b0" @@ derta @@ U"8'b0").asBits, RMax, G_B_derta)
        div2.driverFrom(B_R.asBits, (U"1'b0" @@ derta @@ U"8'b0").asBits, GMax, B_R_derta)
        div3.driverFrom(R_G.asBits, (U"1'b0" @@ derta @@ U"8'b0").asBits, BMax, R_G_derta)


        G_B_derta_add := G_B_derta.asSInt
        B_R_derta_add := B_R_derta.asSInt + 2 @@ S"8'b0"
        R_G_derta_add := R_G_derta.asSInt + 4 @@ S"8'b0"


        val mul60 = AFix.S(8 exp, -8 exp)
        val afixG_B_derta_add = AFix.S(8 exp, -8 exp)
        val afixB_R_derta_add = AFix.S(8 exp, -8 exp)
        val afixR_G_derta_add = AFix.S(8 exp, -8 exp)
        afixG_B_derta_add := G_B_derta_add
        afixB_R_derta_add := B_R_derta_add
        afixR_G_derta_add := R_G_derta_add
        mul60 := S"9'd60" @@ S"8'd0"
        G_B_derta_add_mul := (mul60 * afixG_B_derta_add).roundHalfUp(0).asSInt().resized
        B_R_derta_add_mul := (mul60 * afixB_R_derta_add).roundHalfUp(0).asSInt().resized
        R_G_derta_add_mul := (mul60 * afixR_G_derta_add).roundHalfUp(0).asSInt().resized


        //  val H = SInt(9 bits)
        (R, G, B) := io.dataIn.data
        when(R >= G && R >= B) {
            CMax := R
            RMax := True
            GMax := False
            BMax := False
        } elsewhen (G >= R && G >= B) {
            CMax := G
            RMax := False
            GMax := True
            BMax := False
        } otherwise {
            CMax := B
            RMax := False
            GMax := False
            BMax := True
        }


        when(R <= G && R <= B) {
            CMin := R
        } elsewhen (G <= R && G <= B) {
            CMin := G
        } otherwise {
            CMin := B
        }
        derta := CMax - CMin


        when(dertaEq0) {
            H_D := 0
        } elsewhen (RMaxDelay) {
            when(G_B_derta_add_mul.sign) {
                H_D := (G_B_derta_add_mul +^ 360).asUInt.resized
            } otherwise {
                H_D := G_B_derta_add_mul(8 downto 0).asUInt.resized
            }


        } elsewhen (GMaxDelay) {
            when(B_R_derta_add_mul.sign) {
                H_D := (B_R_derta_add_mul + 360).asUInt.resized
            } otherwise {
                H_D := B_R_derta_add_mul(8 downto 0).asUInt.resized
            }
        } elsewhen (BMaxDelay) {
            when(R_G_derta_add_mul.sign) {
                H_D := (R_G_derta_add_mul + 360).asUInt.resized
            } otherwise {
                H_D := R_G_derta_add_mul(8 downto 0).asUInt.resized
            }
        }
        H := (H_D(8 downto 1) + H_D(0).asUInt)


    }


    val calcS = new Area {
        val S_Div = Bits(17 bits)
        val div = new Div(17, 8)
        div.driverFrom((U"1'd0" @@ derta @@ U"8'd0").asBits, (U"1'd0" @@ CMax @@ U"8'd0").asBits, RegNext(io.dataIn.valid), S_Div)
        val mul255 = AFix.S(8 exp, -8 exp)
        val afixS = AFix.S(8 exp, -8 exp)
        afixS := S_Div.asSInt
        mul255 := S"9'd255" @@ S"8'd0"
        val afix_mul = RegNext(afixS * mul255)
        val afix_mul_r = RegNext(RegNext(afix_mul.roundHalfUp(0)).asUInt())
        val S = Reg(UInt(8 bits))
        val CMaxEq0 = Delay(CMax === 0, 13)
        when(CMaxEq0){
            S := 0
        } otherwise{
            S := afix_mul_r(7 downto 0)
        }
    }


    val calcV = new Area {
        val V = Delay(CMax, 14)
    }


    io.dataOut.valid := Delay(io.dataIn.valid, 15, init = False)
    io.dataOut.data := (calcH.H @@ calcS.S @@ calcV.V).asBits


}


object Rgb2hsv extends App {
    SpinalVerilog(new Rgb2hsv)
}

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1629

    文章

    21729

    浏览量

    602986
  • 图像处理
    +关注

    关注

    27

    文章

    1289

    浏览量

    56722
  • RGB
    RGB
    +关注

    关注

    4

    文章

    798

    浏览量

    58461
  • HSV
    HSV
    +关注

    关注

    0

    文章

    10

    浏览量

    2603

原文标题:FPGA图像处理--RGB转HSV

文章出处:【微信号:FPGA开源工坊,微信公众号:FPGA开源工坊】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    FPGA工程师:如何在FPGA实现状态机?

    安全高效的状态机设计对于任何使用FPGA的工程师而言都是一项重要技能。选择Moore状态机、Mealy状态机还是混合机取决于整个系统的需求。无论选择哪种类型的状态机,充分掌握实现方案所需的工具和技巧,将确保您实现最佳解决方案。本
    发表于 03-29 15:02 1.3w次阅读
    <b class='flag-5'>FPGA</b>工程师:如<b class='flag-5'>何在</b><b class='flag-5'>FPGA</b><b class='flag-5'>中</b><b class='flag-5'>实现</b>状态机?

    何在FPGA实现过零检测器?

    大家好!我想知道如何在FPGA中使用VHDL实现过零检测器。所以我想实现一个数字常数小数鉴别器。 firt部分提供了双极性信号,但我想知道如何在
    发表于 01-29 08:16

    什么是CVSD?其算法分析如何在FPGA实现

    的不足,同时也方便在现场可编程门阵列(FPGA)增加一些其他相关的应用功能,因此在FPGA实现CVSD语音编译码调制功能的前景将是非常广
    发表于 08-07 07:04

    何在FPGA实现实时时钟或时间和日期计数器

    嗨,我是Xilinx FPGA的新手。我该如何在FPGA实现实时时钟或时间和日期计数器?Xilinx是否为Artix 7提供任何RTC核心
    发表于 05-22 12:41

    何在Virtex-7 FPGA实现动态部分配置

    嗨,如何在Virtex-7 FPGA实现动态部分配置?问候,Suresh Palani
    发表于 05-29 11:30

    何在低端FPGA实现DPA的功能?

    FPGA,动态相位调整(DPA)主要是实现LVDS接口接收时对时钟和数据通道的相位补偿,以达到正确接收的目的。那么该如何在低端FPGA
    发表于 04-08 06:47

    请问在FPGA上怎么实现RGB转换到YCbCr?

    本文推导出一种适合在FPGA实现RGB到YCbCr。颜色空间变换的新算法,采用单片FPGA完成电路设计,利用FPGA内嵌DSP核
    发表于 04-29 06:57

    低成本FPGA实现动态相位调整方案

    FPGA,动态相位调整(DPA)主要是实现LVDS接口接收时对时钟和数据通道的相位补偿,以达到正确接收的目的。ALTERA的高端FPGA,如STRATIX(r) 系列
    的头像 发表于 02-16 17:32 1.1w次阅读
    低成本<b class='flag-5'>FPGA</b><b class='flag-5'>中</b><b class='flag-5'>实现</b>动态相位调整方案

    莱迪思FPGA助力玩视科技(HDCVT)实现SDIHDMI解决方案

    近日宣布深圳玩视科技有限公司(HDCVT)采用莱迪思FPGA器件提供的丰富高速SERDES资源和灵活的I/O接口,实现双通道3G SDIHDMI/VGA/RGB桥接。
    发表于 01-04 12:00 1842次阅读

    浅析基于labview的RGBHSV转换

    在labview的应用环境,通过C语言的方式实现RGBHSV的转换。
    发表于 11-15 16:47 19次下载

    ICN6211-6202MIPIRGB MIPILVDS

    集创北方,ICN6211-ICN6202 MIPIRGB,MIPILVDS,芯片在MTK,高通,全志,RK方案商已经调试运用量产 ​
    的头像 发表于 06-24 15:15 3558次阅读
    ICN6211-6202MIPI<b class='flag-5'>转</b><b class='flag-5'>RGB</b> MIPI<b class='flag-5'>转</b>LVDS

    RGBHDMI开源项目

    电子发烧友网站提供《RGBHDMI开源项目.zip》资料免费下载
    发表于 07-21 10:29 14次下载
    <b class='flag-5'>RGB</b><b class='flag-5'>转</b>HDMI开源项目

    如何利用OpenCV进行颜色分类 rgbhsv的区别

    如果光源不稳定,光照变化较大(存在阴影或者亮斑),则利用HSV通道检测就比RGB检测高效得多。光照变化较大时,对RGB三个色道的参数影响都很大,在实际调参过程中会显得非常麻烦,而且效果不理想。
    发表于 08-07 09:52 1405次阅读
    如何利用OpenCV进行颜色分类 <b class='flag-5'>rgb</b>和<b class='flag-5'>hsv</b>的区别

    何在FPGA实现状态机

    FPGA(现场可编程门阵列)实现状态机是一种常见的做法,用于控制复杂的数字系统行为。状态机能够根据当前的输入和系统状态,决定下一步的动作和新的状态。这里,我们将详细探讨如何在
    的头像 发表于 07-18 15:57 566次阅读

    何在FPGA实现随机数发生器

    分享如何在Xilinx Breadboardable Spartan-7 FPGA, CMOD S7实现4位伪随机数发生器(PRNGs)。
    的头像 发表于 08-06 11:20 662次阅读
    如<b class='flag-5'>何在</b><b class='flag-5'>FPGA</b><b class='flag-5'>中</b><b class='flag-5'>实现</b>随机数发生器