Notes d'étude OpenCvSharp 13 - Utilisation d'InRange pour le filtrage de seuil HSV et la génération de dégradés de couleurs

Cible

Introduction à l'espace colorimétrique HSV
Utiliser InRange pour gérer les seuils
Détecter les objets en fonction de la plage de valeurs en pixels de l'espace colorimétrique HSV
Générer des dégradés de couleurs

Espace colorimétrique HSV

HSV (Teinte, Saturation, Valeur) est un espace colorimétrique créé par AR Smith en 1978 basé sur les caractéristiques intuitives de la couleur, également connu sous le nom de modèle Hexcone. Le système de couleurs HSV est un modèle de couleur intuitif pour les utilisateurs. Concernant la couleur, les gens demandent intuitivement "Quelle couleur ? Dans quelle mesure est-il foncé ? Dans quelle mesure est-il clair et foncé ?", et le système de couleurs HSV représente intuitivement cette information.
Chaque couleur est représentée par la teinte (Teinte, H en abrégé), la saturation (Saturation, en abrégé) et la luminosité (Valeur, V en abrégé). Les paramètres de couleur dans ce modèle sont : la teinte (H), la saturation (S) et la luminosité (V).
Le paramètre teinte H représente les informations de couleur, c'est-à-dire la position de la couleur spectrale. Ce paramètre est représenté par un angle, d'une valeur allant de 0° à 360°. Si calculé dans le sens antihoraire à partir du rouge, le rouge est 0°, le vert est 120° et le bleu est 240°. Leurs couleurs complémentaires sont : le jaune est de 60°, le cyan est de 180° et le violet est de 300° ;
saturation S : la plage de valeurs est de 0,0 à 1,0 ;
luminosité V : la plage de valeurs est de 0,0 (noir) à 1,0 (blanc).
H : (Teinte teinte, teinte), S : (Saturation), V : (Hauteur de la valeur). HSV est utile lorsque les objets doivent être segmentés par couleur. La saturation (S) va d'insaturée pour représenter les nuances de gris à complètement saturée (pas de composant blanc). Le canal de luminance (V) décrit la luminosité ou l'intensité. Comme le montre l'image (site officiel de la source de l'image)

Espace colorimétrique HSV

Par rapport à l’espace colorimétrique RVB, il est difficile de segmenter les objets dans les images par couleur.

Espace colorimétrique RVB

Jugement de la portée InRange

Description de la fonction : vérifie si un élément du tableau se trouve entre les éléments de deux autres tableaux.
Pour chaque élément d'un seul canal
dst(I)=lowerb(I) 0 ≤src(I) 0 ≤upperb(I) 0

对于三通道
dst(I)=lowerb(I) 0 ≤src(I) 0 ≤upperb(I) 0 ∧ lowerb(I) 1 ≤src(I) 1 ≤upperb(I) 1 ∧ lowerb(I) 2 ≤ src(I) 2 ≤upérieurb(I) 2

//函数原型1
void InRange(InputArray src,
	InputArray lowerb,
	InputArray upperb,
	OutputArray dst)

//函数原型2
void InRange(InputArray src,
	Scalar lowerb,
	Scalar upperb,
	OutputArray dst)
paramètre illustrer                            
Tableau d'entrée src image d'entrée
InputArray inférieurb
Scalaire inférieurb
Limite inférieure de la plage (inclus)
InputArray supérieur
scalaire supérieur
Limite supérieure de la plage (incluse)
Date d'heure du tableau de sortie Image de sortie (la valeur dans la plage inférieure et supérieure est de 255, sinon elle est de 0)

HSV dans OpenCV

La plage de valeurs de HSV utilisée dans OpenCV est H : [0,180], S : [0,255], V : [0,255], donc la plage de chaque couleur est celle indiquée dans la figure ci-dessous :La plage de valeurs de chaque couleur en HSV

Dessinez les valeurs limites de chaque couleur en HSV dans des blocs de couleur

1. Définissez le tableau ci-dessus comme une matrice

/// <summary>
/// HSV颜色范围
/// </summary>
/// <returns></returns>
private Mat GetHSVRange()
{
    
    
    //使用HSV定义的各颜色范围 6个byte为一组,
    //前三个是对应颜色的最小值,后三个是对应颜色的最大值
    var HSVMinMaxValue = new byte[] {
    
    0,0,0,  //黑min
                                    180,255,46,//黑max
                                    0,0,46,//灰
                                    180,43,220,
                                    0,0,221,//白
                                    180,30,255,
                                    0,43,46,//红1
                                    10,255,255,
                                    156,43,46,//红2
                                    180,255,255,
                                    11,43,46,//橙
                                    25,255,255,
                                    26,43,46,//黄
                                    34,255,255,
                                    35,43,46,//绿
                                    77,255,255,
                                    78,43,46,//青
                                    99,255,255,
                                    100,43,46,//蓝
                                    124,255,255,
                                    125,43,46,//紫
                                    155,255,255};
    var hsvRange = new Mat(HSVMinMaxValue.Length / 3, 1, MatType.CV_8UC3, HSVMinMaxValue);
    return hsvRange;
}

2. Convertissez HSV en BGR, puis dessinez

var HSVRange = GetHSVRange();
var BGRRange = new Mat();
Cv2.CvtColor(HSVRange, BGRRange, ColorConversionCodes.HSV2BGR);
            
int cWidth = 100;
int perRow = width / cWidth - 2;

Mat canvasBGR = new Mat(height, width, MatType.CV_8UC3, Scalar.White);
//将各颜色的上下限画出来
for (int i = 0; i < BGRRange.Rows; i++)
{
    
    
    var bgr = BGRRange.At<Vec3b>(i, 0);
    var color = Scalar.FromVec3b(bgr);
    var rect = new Rect(cWidth * ((i) % perRow + 1), cWidth * ((i) / perRow + 1), cWidth, cWidth);
    Cv2.Rectangle(canvasBGR, rect, color, -1);
}
Utils.ShowWaitDestroy(canvasBGR, "HSV ColorSpace");//显示canvasBGR

L'effet généré est le suivant (pour les valeurs limites supérieure et inférieure​​de noir, gris, blanc, rouge 1, rouge 2, orange, jaune, vert, cyan, bleu et violet) : Générer des couleurs dégradées selon chaque valeur de HSV : après avoir converti HSV en BGR,
Valeur limite de chaque couleur
générez
Couleur du dégradé HSV
à nouveau Couleur dégradé :
Couleur du dégradé BGR
les deux méthodes produisent des résultats légèrement différents.

Exemple de site officiel

Exécutez le code sur le site officiel avec OpenCvSharp et l'effet est le suivant :
Extraire des objets basés sur HSV
comme le montre la figure ci-dessus, l'effet d'une simple extraction d'objets basée sur la plage de limites de couleurs ne peut généralement pas répondre aux exigences de production !

exemple de code

const int maxValueH = 360 / 2;
const int maxValue = 255;
const string winNameSrc = "源图";
const string winNameDst = "HSV对象掩膜";
const string winNameResult = "根据掩膜提取的对象";
//int lowH = 0, lowS = 0, lowV = 0;
//int highH=maxValueH, highS = maxValue, highV = maxValue;
//红色区域
//int lowH = 156, lowS = 43, lowV = 46;
//int highH = 180, highS = 255, highV = 255;
//蓝色区域
int lowH = 100, lowS = 43, lowV = 46;
int highH = 124, highS = 255, highV = 255;

public void Run()
{
    
    
    DrawingHSVRange();

    HSVThreshold();
}

#region HSV Threshold Sample
private void HSVThreshold()
{
    
    
    var fileName = ImagePath.WindowsLogo;
    using var src = new Mat(fileName, ImreadModes.Color);

    Cv2.NamedWindow(winNameSrc);
    Cv2.NamedWindow(winNameDst);
    Cv2.NamedWindow(winNameResult);
    // Trackbars to set thresholds for HSV values
    Cv2.CreateTrackbar("Low H", winNameDst, ref lowH, maxValueH, OnLowHThreshTrackbar);
    Cv2.CreateTrackbar("High H", winNameDst, ref highH, maxValueH, OnHighHTreshTrackbar);
    Cv2.CreateTrackbar("Low S", winNameDst, ref lowS, maxValue, OnLowSThreshTrackbar);
    Cv2.CreateTrackbar("High S", winNameDst, ref highS, maxValue, OnHighSThreshTrackbar);
    Cv2.CreateTrackbar("Low V", winNameDst, ref lowV, maxValue, OnLowVThreshTrackbar);
    Cv2.CreateTrackbar("High V", winNameDst, ref highV, maxValue, OnHighVThreshTrackbar);
    Cv2.ImShow(winNameSrc, src);
    using var dstHSV = new Mat();
    // 将BGR 转为 HSV
    Cv2.CvtColor(src, dstHSV, ColorConversionCodes.BGR2HSV);            
    using var dstThreshold = new Mat();
    while (true)
    {
    
    
        // 使用InRange根据HSV的最小、最大值检测对象
        Cv2.InRange(dstHSV, new Scalar(lowH, lowS, lowV), new Scalar(highH, highS, highV), dstThreshold);

        // 对象掩膜
        Cv2.ImShow(winNameDst, dstThreshold);

        var copyImg = new Mat();
        src.CopyTo(copyImg, dstThreshold);
        
        Cv2.ImShow(winNameResult, copyImg);
        char key = (char)Cv2.WaitKey(50);
        if (key == 'q' || key == 27)
        {
    
    
            break;
        }
    }
    Cv2.DestroyAllWindows();
}

void OnLowHThreshTrackbar(int pos, IntPtr userData)
{
    
    
    lowH = Math.Min(highH - 1, pos);
    Cv2.SetTrackbarPos("Low H", winNameDst, lowH);
}

void OnHighHTreshTrackbar(int pos, IntPtr userData)
{
    
    
    highH = Math.Max(pos, lowH + 1);
    Cv2.SetTrackbarPos("High H", winNameDst, highH);
}

void OnLowSThreshTrackbar(int pos, IntPtr userData)
{
    
    
    lowS = Math.Min(highS - 1, pos);
    Cv2.SetTrackbarPos("Low S", winNameDst, lowS);
}
void OnHighSThreshTrackbar(int pos, IntPtr userData)
{
    
    
    highS = Math.Max(pos, lowS + 1);
    Cv2.SetTrackbarPos("High S", winNameDst, highS);
}
void OnLowVThreshTrackbar(int pos, IntPtr userData)
{
    
    
    lowV = Math.Min(highV - 1, pos);
    Cv2.SetTrackbarPos("Low V", winNameDst, lowV);
}
void OnHighVThreshTrackbar(int pos, IntPtr userData)
{
    
    
    highV = Math.Max(pos, lowV + 1);
    Cv2.SetTrackbarPos("High V", winNameDst, highV);
}
#endregion

/// <summary>
/// 按HSV绘制
/// </summary>
private void DrawingHSVRange()
{
    
    
    var width = 1600;
    var height = 800;

    string ColorName = "黑、灰、白、红1、红2、橙、黄、绿、青、蓝、紫";
    var HSVRange = GetHSVRange();
    var BGRRange = new Mat();
    Cv2.CvtColor(HSVRange, BGRRange, ColorConversionCodes.HSV2BGR);
                
    int cWidth = 100;
    int perRow = width / cWidth - 2;

    Mat canvasBGR = new Mat(height, width, MatType.CV_8UC3, Scalar.White);
    //将各颜色的上下限画出来
    for (int i = 0; i < BGRRange.Rows; i++)
    {
    
    
        var bgr = BGRRange.At<Vec3b>(i, 0);
        var color = Scalar.FromVec3b(bgr);
        var rect = new Rect(cWidth * ((i) % perRow + 1), cWidth * ((i) / perRow + 1), cWidth, cWidth);
        Cv2.Rectangle(canvasBGR, rect, color, -1);
    }
    Utils.ShowWaitDestroy(canvasBGR, "HSV ColorSpace");

    //初始化一张HSV,白底画布,注意HSV中白色是(0,0,255)
    Mat canvasHSV = new Mat(height, width, MatType.CV_8UC3, new Scalar(0, 0, 255));
    //通过HSV的递增生成渐变色
    GenerateGradientColor(canvasHSV, HSVRange, "HSV");
    //将HSV转成BGR显示
    Cv2.CvtColor(canvasHSV, canvasHSV, ColorConversionCodes.HSV2BGR);
    Utils.ShowWaitDestroy(canvasHSV, "HSV:"+ ColorName);
    
    //初始化一张BGR,白底画布
    canvasBGR = new Mat(height, width, MatType.CV_8UC3, Scalar.White);
    GenerateGradientColor(canvasBGR, BGRRange, "BGR");
    Utils.ShowWaitDestroy(canvasBGR, "BGR:"+ ColorName);
    Cv2.DestroyAllWindows();
}
/// <summary>
/// 根据颜色范围生成渐变色
/// </summary>
/// <param name="canvas">画布</param>
/// <param name="colorRange">颜色范围(最小值、最大值)</param>
/// <param name="colorSpace"></param>
private void GenerateGradientColor(Mat canvas,Mat colorRange,string colorSpace)
{
    
    
    //两边的边距
    int edgeDistance = 160;
    //各渐变色的跨度
    int stepWdith = canvas.Cols - edgeDistance * 2;
    //各渐变色的高度
    int rowHeight = 60;
    //通过颜色递增生成渐变色
    for (int i = 0; i < colorRange.Rows - 1; i += 2)
    {
    
    
        var minVal = colorRange.At<Vec3b>(i, 0);//颜色最小值
        var maxVal = colorRange.At<Vec3b>(i + 1, 0);//颜色最大值 转BGR时,各通道的值大、小有变
        var stepB = Math.Abs(1.0D * (maxVal.Item0 - minVal.Item0) / stepWdith);
        var stepG = Math.Abs(1.0D * (maxVal.Item1 - minVal.Item1) / stepWdith);
        var stepR = Math.Abs(1.0D * (maxVal.Item2 - minVal.Item2) / stepWdith);
        int rowOffset = rowHeight * (i / 2 + 1);
        for (int step = 0; step <= stepWdith; step++)
        {
    
    
            //生成渐变色
            var colorVec = new Vec3b((byte)(Math.Min(minVal.Item0,maxVal.Item0) + stepB * step),
                                     (byte)(Math.Min(minVal.Item1, maxVal.Item1) + stepG * step),
                                     (byte)(Math.Min(minVal.Item2, maxVal.Item2) + stepR * step));
            //生成rowHeigh行
            for (int row = 0; row < rowHeight; row++)
            {
    
    
                canvas.At<Vec3b>(row + rowHeight * (i / 2 + 1), edgeDistance + step) = colorVec;
            }
            //两边加文字
            if (step == 0)
            {
    
    
                PutText(canvas, new Point(5, rowOffset + rowHeight / 2), colorSpace, colorVec);
            }
            else if (step == stepWdith)
            {
    
    
                PutText(canvas, new Point((canvas.Cols - edgeDistance) + 5, rowOffset + rowHeight / 2), colorSpace, colorVec);
            }
        }                
    }    
}


//绘制渐变色两字的文字
private void PutText(Mat src, Point org, string text, Vec3b colorVec)
{
    
    
    Cv2.PutText(src, $"{
      
      text}({
      
      colorVec.Item0},{
      
      colorVec.Item1},{
      
      colorVec.Item2})", org, HersheyFonts.HersheyTriplex, 0.5, Scalar.Black);
}

/// <summary>
/// HSV颜色范围
/// </summary>
/// <returns></returns>
private Mat GetHSVRange()
{
    
    
    //使用HSV定义的各颜色范围 6个byte为一组,
    //前三个是对应颜色的最小值,后三个是对应颜色的最大值
    var HSVMinMaxValue = new byte[] {
    
    0,0,0,  //黑min
                                    180,255,46,//黑max
                                    0,0,46,//灰
                                    180,43,220,
                                    0,0,221,//白
                                    180,30,255,
                                    0,43,46,//红1
                                    10,255,255,
                                    156,43,46,//红2
                                    180,255,255,
                                    11,43,46,//橙
                                    25,255,255,
                                    26,43,46,//黄
                                    34,255,255,
                                    35,43,46,//绿
                                    77,255,255,
                                    78,43,46,//青
                                    99,255,255,
                                    100,43,46,//蓝
                                    124,255,255,
                                    125,43,46,//紫
                                    155,255,255};
    var hsvRange = new Mat(HSVMinMaxValue.Length / 3, 1, MatType.CV_8UC3, HSVMinMaxValue);
    return hsvRange;
}

Référence
https://docs.opencv.org/4.7.0/da/d97/tutorial_threshold_inRange.html

Je suppose que tu aimes

Origine blog.csdn.net/TyroneKing/article/details/129871720
conseillé
Classement