我正在尝试在HSV维度上进行Sobel运算符(根据我的指南曾在HSV中进行过此说明,但我不明白为什么它在HSV上比在RGB上更好地工作)。
我建立了一个将RGB转换为HSV的函数。虽然我对C++的知识不多,但我对图像处理感到困惑,因此我尝试使代码尽可能简单,这意味着(在此阶段)我不在乎时间或空间。
从结果看,我得到了灰度bmp照片,我的V和S看起来不错,但我的H看起来很乱。
我在这里有2个问题:
1.与原始照片相比,普通的H灰度灰度照片看起来如何?
2.我在代码中哪里写错了:

   void RGBtoHSV(unsigned char image[][NUMBER_OF_COLUMNS][NUMBER_OF_COLORS],
float Him[][NUMBER_OF_COLUMNS],
float Vim[][NUMBER_OF_COLUMNS],
float Sim[][NUMBER_OF_COLUMNS])
{

double Rn, Gn, Bn;

double   C;
double H, S, V;

for (int row = 0; row < NUMBER_OF_ROWS; row++)
{
    for (int column = 0; column < NUMBER_OF_COLUMNS; column++)
    {
        Rn = (1.0*image[row][column][R]) / 255;
        Gn = (1.0*image[row][column][G] )/ 255;
        Bn = (1.0*image[row][column][B] )/ 255;

        //double RGBn[3] = { Rn, Gn, Bn };

        double max = Rn;
        if (max < Gn) max = Gn;
        if (max < Bn) max = Bn;
        double min = Rn;
        if (min > Gn) min = Gn;
        if (min > Bn) min = Bn;

        C = max - min;

        H = 0;
        if (max==0)
        {
            S = 0;
            H = -1; //undifined;
            V = max;
        }
        else
        {

        /*  if (max == Rn)
                H = (60.0* ((int)((Gn - Bn) / C) % 6));
            else if (max == Gn)
                H = 60.0*( (Bn - Rn)/C + 2);
            else
                H = 60.0*( (Rn - Gn)/C + 4);
            */

            if (max == Rn)
                H = (   60.0* ( (Gn - Bn) / C) )   ;
            else if (max == Gn)
                H = 60.0*((Bn - Rn) / C + 2);
            else
                H = 60.0*((Rn - Gn) / C + 4);

            V = max; //AKA lightness
            S = C / max; //saturation
        }


        while (H < 0)
            H += 360;
        while (H>360)
            H -= 360;

        Him[row][column] = (float)H;

        Vim[row][column] = (float)V;
        Sim[row][column] = (float)S;
    }
}
}

还有我的hsvtorgb:
void HSVtoRGB(unsigned char image[][NUMBER_OF_COLUMNS][NUMBER_OF_COLORS],
float Him[][NUMBER_OF_COLUMNS],
float Vim[][NUMBER_OF_COLUMNS],
float Sim[][NUMBER_OF_COLUMNS])
{

double R1, G1, B1;

double   C;
double   V;
double S;
double H;
int Htag;
double Htag2;
double x;
double m;

for (int row = 0; row < NUMBER_OF_ROWS; row++)
{
    for (int column = 0; column < NUMBER_OF_COLUMNS; column++)
    {
        H = (double)Him[row][column];
        S = (double)Sim[row][column];
        V = (double)Vim[row][column];


        C = V*S;

        Htag = (int) (H / 60.0);
        Htag2 = H/ 60.0;


        //x = C*(1 - abs(Htag % 2 - 1));
        double tmp1 = fmod(Htag2, 2);
        double temp=(1 - abs(tmp1 - 1));
        x = C*temp;
        //switch (Htag)
        switch (Htag)
        {
        case 0 :
            R1 = C;
            G1 = x;
            B1 = 0;
            break;
        case 1:
            R1 = x;
            G1 = C;
            B1 = 0;
            break;
        case 2:
            R1 = 0;
            G1 = C;
            B1 = x;
            break;
        case 3:
            R1 = 0;
            G1 = x;
            B1 = C;
            break;
        case 4:
            R1 = x;
            G1 = 0;
            B1 = C;
            break;
        case 5:
            R1 = C;
            G1 = 0;
            B1 = x;
            break;
        default:
            R1 = 0;
            G1 = 0;
            B1 = 0;
            break;

        }


        m = V - C;
   //this is also good change I found
        //image[row][column][R] = unsigned char( (R1 + m)*255);
        //image[row][column][G] = unsigned char( (G1 + m)*255);
        //image[row][column][B] = unsigned char( (B1 + m)*255);

        image[row][column][R] = round((R1 + m) * 255);
        image[row][column][G] = round((G1 + m) * 255);
        image[row][column][B] = round((B1 + m) * 255);



            }
      }
   }


   void HSVfloattoGrayconvert(unsigned char grayimage[NUMBER_OF_ROWS]        [NUMBER_OF_COLUMNS], float hsvimage[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS], char hsv)
  {
//grayimage , flaotimage , h/s/v
   float factor;
if (hsv == 'h' || hsv == 'H') factor = (float) 1 / 360;
else factor = 1;
for (int row = 0; row < NUMBER_OF_ROWS; row++)
{
    for (int column = 0; column < NUMBER_OF_COLUMNS; column++)
    {
        grayimage[row][column] = (unsigned char) (0.5f + 255.0f * (float)hsvimage[row][column] / factor);
          }
      }
 }

和我的主要:
 unsigned char ColorImage1[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]   [NUMBER_OF_COLORS];
float Himage[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
float Vimage[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
float Simage[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];

 unsigned char ColorImage2[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]   [NUMBER_OF_COLORS];

unsigned char HimageGray[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
unsigned char VimageGray[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
unsigned char SimageGray[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];

unsigned char HAfterSobel[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
unsigned char VAfterSobel[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
unsigned char SAfterSobal[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];

   unsigned char HSVcolorAfterSobal[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS][NUMBER_OF_COLORS];

unsigned char RGBAfterSobal[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS][NUMBER_OF_COLORS];


int KernelX[3][3] = {
{-1,0,+1}, {-2,0,2}, {-1,0,1 }
};

  int KernelY[3][3] = {
   {-1,-2,-1}, {0,0,0}, {1,2,1}
  };

  void main()
{

//work
LoadBgrImageFromTrueColorBmpFile(ColorImage1, "P22A.bmp");

// add noise
AddSaltAndPepperNoiseRGB(ColorImage1, 350, 255);
StoreBgrImageAsTrueColorBmpFile(ColorImage1, "saltandpepper.bmp");
AddGaussNoiseCPPstileRGB(ColorImage1, 0.0, 1.0);
StoreBgrImageAsTrueColorBmpFile(ColorImage1, "Saltandgauss.bmp");

//saves hsv in float array
RGBtoHSV(ColorImage1, Himage, Vimage, Simage);

//saves hsv float arrays in unsigned char arrays
HSVfloattoGrayconvert(HimageGray, Himage, 'h');
HSVfloattoGrayconvert(VimageGray, Vimage, 'v');
HSVfloattoGrayconvert(SimageGray, Simage, 's');


StoreGrayImageAsGrayBmpFile(HimageGray, "P22H.bmp");
StoreGrayImageAsGrayBmpFile(VimageGray, "P22V.bmp");
StoreGrayImageAsGrayBmpFile(SimageGray, "P22S.bmp");

    WaitForUserPressKey();

  }

编辑:更改代码+添加方程式的来源:
求出:对于方程式:
  • http://www.rapidtables.com/convert/color/hsv-to-rgb.htm
  • http://www.rapidtables.com/convert/color/rgb-to-hsv.htm

  • 编辑3:
    @gpasch建议并使用better reference并删除mod6,我现在能够恢复RGB原始照片!但是不幸的是现在我的H色灰度照片比以前更困惑了。
    我将编辑有关的代码,这样它将获得有关如何保存H灰度照片的更多信息。

    最佳答案



    这取决于您要实现的目标。例如,如果您尝试基于亮度进行边缘检测,那么仅说V通道可能比处理RGB的所有三个通道然后将它们组合起来要简单。



    您会看到颜色相似的区域显示为相似的灰色阴影,而对于真实世界的场景,您仍然会看到渐变。但是,如果在空间上相邻的区域的色相相距甚远,则会出现急剧的跳跃。形状通常是可以识别的。



    您的代码有两个主要问题。首先是HSVfloattoGrayconvert中的色相缩放错误。您的代码正在设置factor=1.0/360.0f,然后除以系数,这意味着它乘以360。如果仅乘以系数,它将产生预期的输出。这是因为较早的计算对S和V使用归一化值(0..1),对H使用以度为单位的 Angular ,因此您需要除以360才能归一化H。

    其次,转换回RGB有一个问题,主要与计算Htag有关,在这种情况下,您想要用于计算x的原始值,但仅在打开扇区时才需要floor

    请注意,尽管有@gpasch的建议,但mod 6操作实际上是正确的。这是因为您使用的转换基于HSV的六边形颜色空间模型,并且用于确定您的颜色位于哪个扇区。对于连续模型,您可以使用径向转换,而径向转换则略有不同。两者在Wikipedia上都有很好的解释。

    我接受了您的代码,添加了一些函数来生成输入数据并保存输出文件,使其完全独立,并修复了上述错误,同时对源代码进行了最小的更改。

    给定以下生成的输入图像:

    c&#43;&#43; - 实现RGBtoHSV C&#43;&#43;,错误的H输出-LMLPHP

    提取的色相通道为:

    c&#43;&#43; - 实现RGBtoHSV C&#43;&#43;,错误的H输出-LMLPHP

    饱和通道为:

    c&#43;&#43; - 实现RGBtoHSV C&#43;&#43;,错误的H输出-LMLPHP

    最后的值(value):

    c&#43;&#43; - 实现RGBtoHSV C&#43;&#43;,错误的H输出-LMLPHP

    将HSV固定为RGB转换后,我验证了生成的输出图像与原始图像匹配。

    下面是更新的代码(如上所述,已进行了最小的更改以进行独立测试):

    #include <string>
    #include <cmath>
    #include <cstdlib>
    
    enum ColorIndex
    {
        R = 0,
        G = 1,
        B = 2,
    };
    
    namespace
    {
        const unsigned NUMBER_OF_COLUMNS   = 256;
        const unsigned NUMBER_OF_ROWS      = 256;
        const unsigned NUMBER_OF_COLORS    = 3;
    };
    
    void RGBtoHSV(unsigned char image[][NUMBER_OF_COLUMNS][NUMBER_OF_COLORS],
                  float Him[][NUMBER_OF_COLUMNS],
                  float Vim[][NUMBER_OF_COLUMNS],
                  float Sim[][NUMBER_OF_COLUMNS])
    {
        double Rn, Gn, Bn;
        double   C;
        double H, S, V;
    
        for (int row = 0; row < NUMBER_OF_ROWS; row++)
        {
            for (int column = 0; column < NUMBER_OF_COLUMNS; column++)
            {
                Rn = image[row][column][R] / 255.0;
                Gn = image[row][column][G] / 255.0;
                Bn = image[row][column][B] / 255.0;
    
                double max = Rn;
                if (max < Gn) max = Gn;
                if (max < Bn) max = Bn;
                double min = Rn;
                if (min > Gn) min = Gn;
                if (min > Bn) min = Bn;
    
                C = max - min;
    
                H = 0;
                if (max==0)
                {
                    S = 0;
                    H = 0; // Undefined
                    V = max;
                }
                else
                {
                    if (max == Rn)
                        H = 60.0*fmod((Gn - Bn) / C, 6.0);
                    else if (max == Gn)
                        H = 60.0*((Bn - Rn) / C + 2);
                    else
                        H = 60.0*((Rn - Gn) / C + 4);
    
                    V = max; //AKA lightness
                    S = C / max; //saturation
                }
    
    
                while (H < 0)
                    H += 360.0;
                while (H > 360)
                    H -= 360.0;
    
                Him[row][column] = (float)H;
                Vim[row][column] = (float)V;
                Sim[row][column] = (float)S;
            }
        }
    }
    
    void HSVtoRGB(unsigned char image[][NUMBER_OF_COLUMNS][NUMBER_OF_COLORS],
                  float Him[][NUMBER_OF_COLUMNS],
                  float Vim[][NUMBER_OF_COLUMNS],
                  float Sim[][NUMBER_OF_COLUMNS])
    {
    
        double R1, G1, B1;
    
        double   C;
        double   V;
        double S;
        double H;
        double Htag;
        double x;
        double m;
    
        for (int row = 0; row < NUMBER_OF_ROWS; row++)
        {
            for (int column = 0; column < NUMBER_OF_COLUMNS; column++)
            {
                H = (double)Him[row][column];
                S = (double)Sim[row][column];
                V = (double)Vim[row][column];
    
                C = V*S;
    
                Htag = H / 60.0;
    
                double x = C*(1.0 - fabs(fmod(Htag, 2.0) - 1.0));
    
                int i = floor(Htag);
                switch (i)
                {
                    case 0 :
                        R1 = C;
                        G1 = x;
                        B1 = 0;
                        break;
                    case 1:
                        R1 = x;
                        G1 = C;
                        B1 = 0;
                        break;
                    case 2:
                        R1 = 0;
                        G1 = C;
                        B1 = x;
                        break;
                    case 3:
                        R1 = 0;
                        G1 = x;
                        B1 = C;
                        break;
                    case 4:
                        R1 = x;
                        G1 = 0;
                        B1 = C;
                        break;
                    case 5:
                        R1 = C;
                        G1 = 0;
                        B1 = x;
                        break;
                    default:
                        R1 = 0;
                        G1 = 0;
                        B1 = 0;
                        break;
    
                }
    
                m = V - C;
    
                image[row][column][R] = round((R1 + m) * 255);
                image[row][column][G] = round((G1 + m) * 255);
                image[row][column][B] = round((B1 + m) * 255);
            }
        }
    }
    
    
    void HSVfloattoGrayconvert(unsigned char grayimage[][NUMBER_OF_COLUMNS], float hsvimage[][NUMBER_OF_COLUMNS], char hsv)
    {
    //grayimage , flaotimage , h/s/v
        float factor;
        if (hsv == 'h' || hsv == 'H') factor = 1.0f/360.0f;
        else factor = 1.0f;
        for (int row = 0; row < NUMBER_OF_ROWS; row++)
        {
            for (int column = 0; column < NUMBER_OF_COLUMNS; column++)
            {
                grayimage[row][column] = (unsigned char) (0.5f + 255.0f * (float)hsvimage[row][column] * factor);
            }
        }
    }
    
    
    int KernelX[3][3] = {
        {-1,0,+1}, {-2,0,2}, {-1,0,1 }
    };
    
    int KernelY[3][3] = {
        {-1,-2,-1}, {0,0,0}, {1,2,1}
    };
    
    void GenerateTestImage(unsigned char image[][NUMBER_OF_COLUMNS][NUMBER_OF_COLORS])
    {
        for (unsigned y = 0; y < NUMBER_OF_ROWS; y++)
        {
            for (unsigned x = 0; x < NUMBER_OF_COLUMNS; x++)
            {
                image[y][x][R] = x % 256;
                image[y][x][G] = y % 256;
                image[y][x][B] = (255-x) % 256;
            }
        }
    }
    
    void GenerateTestImage(unsigned char image[][NUMBER_OF_COLUMNS])
    {
        for (unsigned y = 0; y < NUMBER_OF_ROWS; y++)
        {
            for (unsigned x = 0; x < NUMBER_OF_COLUMNS; x++)
            {
                image[x][y] = x % 256;
            }
        }
    }
    
    // Color (three channel) images
    void SaveImage(unsigned char image[][NUMBER_OF_COLUMNS][NUMBER_OF_COLORS], const std::string& filename)
    {
        FILE* fp = fopen(filename.c_str(), "w");
        fprintf(fp, "P6\n%u %u\n255\n", NUMBER_OF_COLUMNS, NUMBER_OF_ROWS);
        fwrite(image, NUMBER_OF_COLORS, NUMBER_OF_ROWS*NUMBER_OF_COLUMNS, fp);
        fclose(fp);
    }
    
    // Grayscale (single channel) images
    void SaveImage(unsigned char image[][NUMBER_OF_COLUMNS], const std::string& filename)
    {
        FILE* fp = fopen(filename.c_str(), "w");
        fprintf(fp, "P5\n%u %u\n255\n", NUMBER_OF_COLUMNS, NUMBER_OF_ROWS);
        fwrite(image, 1, NUMBER_OF_ROWS*NUMBER_OF_COLUMNS, fp);
        fclose(fp);
    }
    
    unsigned char ColorImage1[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS][NUMBER_OF_COLORS];
    unsigned char Himage[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
    unsigned char Simage[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
    unsigned char Vimage[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
    float HimageGray[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
    float SimageGray[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
    float VimageGray[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
    
    int main()
    {
        // Test input
        GenerateTestImage(ColorImage1);
        SaveImage(ColorImage1, "test_input.ppm");
    
        //saves hsv in float array
        RGBtoHSV(ColorImage1, HimageGray, VimageGray, SimageGray);
    
        //saves hsv float arrays in unsigned char arrays
        HSVfloattoGrayconvert(Himage, HimageGray, 'h');
        HSVfloattoGrayconvert(Vimage, VimageGray, 'v');
        HSVfloattoGrayconvert(Simage, SimageGray, 's');
    
        SaveImage(Himage, "P22H.pgm");
        SaveImage(Vimage, "P22V.pgm");
        SaveImage(Simage, "P22S.pgm");
    
        // Convert back to get the original test image
        HSVtoRGB(ColorImage1, HimageGray, VimageGray, SimageGray);
        SaveImage(ColorImage1, "test_output.ppm");
    
        return 0;
    }
    

    输入图像是通过非常简单的算法生成的,该算法为我们提供了每个维度的渐变,因此我们可以轻松地检查和验证预期的输出。我使用了ppm/pgm文件,因为它们比BMP更易于编写和移植。

    希望这会有所帮助-如果您有任何疑问,请告诉我。

    关于c++ - 实现RGBtoHSV C++,错误的H输出,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37801087/

    10-12 20:43