0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何在FPGA中實(shí)現(xiàn)RGB轉(zhuǎn)HSV

FPGA開(kāi)源工坊 ? 來(lái)源:FPGA開(kāi)源工坊 ? 2023-07-02 11:49 ? 次閱讀

HSV色彩空間相對(duì)于RGB色彩空間更適合做顏色追蹤,分割顏色等。那么RGB色彩空間要怎么轉(zhuǎn)變?yōu)镠SV色彩空間呢。

轉(zhuǎn)換公式如下:

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

需要注意的是在OpenCV中為了顯示HSV色彩空間的內(nèi)容會(huì)將H的值除以2,S的值和V的值是要乘以255。

FPGA中實(shí)現(xiàn)RGB轉(zhuǎn)HSV的話(huà),上面公式中第一步除以255的歸一化是可以不做的。因?yàn)樵贖和S的計(jì)算中255可以約掉的,如下所示。而在V的值需要乘以255來(lái)顯示,所以也可以不除以255.

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

如R,G,B為169 152 133的值計(jì)算過(guò)程如下:

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

定義如下

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

在計(jì)算中需要使用除法器:

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

因?yàn)?bit的整數(shù),8bit小數(shù)的有符號(hào)數(shù),所以數(shù)據(jù)位寬為17bit。

仿真結(jié)果如下:

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

可以看到ref和dut之間有誤差,這個(gè)是因?yàn)橛?jì)算過(guò)程中采用了8bit的定點(diǎn)小數(shù)造成的,如果小數(shù)位寬擴(kuò)大,那么可以減少誤差。

仿真用的計(jì)分板:

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)
}

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • FPGA
    +關(guān)注

    關(guān)注

    1625

    文章

    21622

    瀏覽量

    601241
  • 圖像處理
    +關(guān)注

    關(guān)注

    27

    文章

    1275

    瀏覽量

    56577
  • RGB
    RGB
    +關(guān)注

    關(guān)注

    4

    文章

    797

    瀏覽量

    58338
  • HSV
    HSV
    +關(guān)注

    關(guān)注

    0

    文章

    10

    瀏覽量

    2594

原文標(biāo)題:FPGA圖像處理--RGB轉(zhuǎn)HSV

文章出處:【微信號(hào):FPGA開(kāi)源工坊,微信公眾號(hào):FPGA開(kāi)源工坊】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    FPGA工程師:如何在FPGA實(shí)現(xiàn)狀態(tài)機(jī)?

    安全高效的狀態(tài)機(jī)設(shè)計(jì)對(duì)于任何使用FPGA的工程師而言都是一項(xiàng)重要技能。選擇Moore狀態(tài)機(jī)、Mealy狀態(tài)機(jī)還是混合機(jī)取決于整個(gè)系統(tǒng)的需求。無(wú)論選擇哪種類(lèi)型的狀態(tài)機(jī),充分掌握實(shí)現(xiàn)方案所需的工具和技巧,將確保您實(shí)現(xiàn)最佳解決方案。本
    發(fā)表于 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'>實(shí)現(xiàn)</b>狀態(tài)機(jī)?

    何在FPGA實(shí)現(xiàn)過(guò)零檢測(cè)器?

    大家好!我想知道如何在FPGA中使用VHDL實(shí)現(xiàn)過(guò)零檢測(cè)器。所以我想實(shí)現(xiàn)一個(gè)數(shù)字常數(shù)小數(shù)鑒別器。 firt部分提供了雙極性信號(hào),但我想知道如何在
    發(fā)表于 01-29 08:16

    什么是CVSD?其算法分析如何在FPGA實(shí)現(xiàn)?

    的不足,同時(shí)也方便在現(xiàn)場(chǎng)可編程門(mén)陣列(FPGA)增加一些其他相關(guān)的應(yīng)用功能,因此在FPGA實(shí)現(xiàn)CVSD語(yǔ)音編譯碼調(diào)制功能的前景將是非常廣
    發(fā)表于 08-07 07:04

    何在FPGA實(shí)現(xiàn)實(shí)時(shí)時(shí)鐘或時(shí)間和日期計(jì)數(shù)器

    嗨,我是Xilinx FPGA的新手。我該如何在FPGA實(shí)現(xiàn)實(shí)時(shí)時(shí)鐘或時(shí)間和日期計(jì)數(shù)器?Xilinx是否為Artix 7提供任何RTC核心
    發(fā)表于 05-22 12:41

    何在Virtex-7 FPGA實(shí)現(xiàn)動(dòng)態(tài)部分配置

    嗨,如何在Virtex-7 FPGA實(shí)現(xiàn)動(dòng)態(tài)部分配置?問(wèn)候,Suresh Palani
    發(fā)表于 05-29 11:30

    何在低端FPGA實(shí)現(xiàn)DPA的功能?

    FPGA,動(dòng)態(tài)相位調(diào)整(DPA)主要是實(shí)現(xiàn)LVDS接口接收時(shí)對(duì)時(shí)鐘和數(shù)據(jù)通道的相位補(bǔ)償,以達(dá)到正確接收的目的。那么該如何在低端FPGA
    發(fā)表于 04-08 06:47

    請(qǐng)問(wèn)在FPGA上怎么實(shí)現(xiàn)RGB轉(zhuǎn)換到Y(jié)CbCr?

    本文推導(dǎo)出一種適合在FPGA實(shí)現(xiàn)RGB到Y(jié)CbCr。顏色空間變換的新算法,采用單片FPGA完成電路設(shè)計(jì),利用FPGA內(nèi)嵌DSP核
    發(fā)表于 04-29 06:57

    低成本FPGA實(shí)現(xiàn)動(dòng)態(tài)相位調(diào)整方案

    FPGA,動(dòng)態(tài)相位調(diào)整(DPA)主要是實(shí)現(xiàn)LVDS接口接收時(shí)對(duì)時(shí)鐘和數(shù)據(jù)通道的相位補(bǔ)償,以達(dá)到正確接收的目的。ALTERA的高端FPGA,如STRATIX(r) 系列
    的頭像 發(fā)表于 02-16 17:32 ?1.1w次閱讀
    低成本<b class='flag-5'>FPGA</b><b class='flag-5'>中</b><b class='flag-5'>實(shí)現(xiàn)</b>動(dòng)態(tài)相位調(diào)整方案

    萊迪思FPGA助力玩視科技(HDCVT)實(shí)現(xiàn)SDI轉(zhuǎn)HDMI解決方案

    近日宣布深圳玩視科技有限公司(HDCVT)采用萊迪思FPGA器件提供的豐富高速SERDES資源和靈活的I/O接口,實(shí)現(xiàn)雙通道3G SDI轉(zhuǎn)HDMI/VGA/RGB橋接。
    發(fā)表于 01-04 12:00 ?1804次閱讀

    淺析基于labview的RGBHSV轉(zhuǎn)換

    在labview的應(yīng)用環(huán)境,通過(guò)C語(yǔ)言的方式實(shí)現(xiàn)RGBHSV的轉(zhuǎn)換。
    發(fā)表于 11-15 16:47 ?19次下載

    ICN6211-6202MIPI轉(zhuǎn)RGB MIPI轉(zhuǎn)LVDS

    集創(chuàng)北方,ICN6211-ICN6202 MIPI轉(zhuǎn)RGB,MIPI轉(zhuǎn)LVDS,芯片在MTK,高通,全志,RK方案商已經(jīng)調(diào)試運(yùn)用量產(chǎn) ?
    的頭像 發(fā)表于 06-24 15:15 ?3455次閱讀
    ICN6211-6202MIPI<b class='flag-5'>轉(zhuǎn)</b><b class='flag-5'>RGB</b> MIPI<b class='flag-5'>轉(zhuǎn)</b>LVDS

    RGB轉(zhuǎn)HDMI開(kāi)源項(xiàng)目

    電子發(fā)燒友網(wǎng)站提供《RGB轉(zhuǎn)HDMI開(kāi)源項(xiàng)目.zip》資料免費(fèi)下載
    發(fā)表于 07-21 10:29 ?14次下載
    <b class='flag-5'>RGB</b><b class='flag-5'>轉(zhuǎn)</b>HDMI開(kāi)源項(xiàng)目

    如何利用OpenCV進(jìn)行顏色分類(lèi) rgbhsv的區(qū)別

    如果光源不穩(wěn)定,光照變化較大(存在陰影或者亮斑),則利用HSV通道檢測(cè)就比RGB檢測(cè)高效得多。光照變化較大時(shí),對(duì)RGB三個(gè)色道的參數(shù)影響都很大,在實(shí)際調(diào)參過(guò)程中會(huì)顯得非常麻煩,而且效果不理想。
    發(fā)表于 08-07 09:52 ?1280次閱讀
    如何利用OpenCV進(jìn)行顏色分類(lèi) <b class='flag-5'>rgb</b>和<b class='flag-5'>hsv</b>的區(qū)別

    何在FPGA實(shí)現(xiàn)狀態(tài)機(jī)

    FPGA(現(xiàn)場(chǎng)可編程門(mén)陣列)實(shí)現(xiàn)狀態(tài)機(jī)是一種常見(jiàn)的做法,用于控制復(fù)雜的數(shù)字系統(tǒng)行為。狀態(tài)機(jī)能夠根據(jù)當(dāng)前的輸入和系統(tǒng)狀態(tài),決定下一步的動(dòng)作和新的狀態(tài)。這里,我們將詳細(xì)探討如何在
    的頭像 發(fā)表于 07-18 15:57 ?430次閱讀

    何在FPGA實(shí)現(xiàn)隨機(jī)數(shù)發(fā)生器

    分享如何在Xilinx Breadboardable Spartan-7 FPGA, CMOD S7實(shí)現(xiàn)4位偽隨機(jī)數(shù)發(fā)生器(PRNGs)。
    的頭像 發(fā)表于 08-06 11:20 ?548次閱讀
    如<b class='flag-5'>何在</b><b class='flag-5'>FPGA</b><b class='flag-5'>中</b><b class='flag-5'>實(shí)現(xiàn)</b>隨機(jī)數(shù)發(fā)生器