El algoritmo de cuenca hidrográfica OpenCV implementa la segmentación de imágenes (colorear soja) C #

El método de segmentación de cuencas es un método matemático de segmentación morfológica basado en la teoría de la topología. Su idea básica es considerar la imagen como una topografía topológica en geodesia. El valor de gris de cada píxel en la imagen representa la altitud de ese punto. Cada mínimo local y su área de influencia se denomina cuenca hidrográfica y los límites de la cuenca hidrográfica forman una cuenca hidrográfica. El concepto y formación de cuencas hidrográficas se puede ilustrar simulando el proceso de inmersión. Se perfora un pequeño agujero en la superficie de cada mínimo local y luego todo el modelo se sumerge lentamente en agua. A medida que la inmersión se profundiza, el dominio de influencia de cada mínimo local se expande lentamente hacia afuera. La construcción de una presa en la confluencia de cuencas forma un cuenca.
Insertar descripción de la imagen aquí

Pasos generales para la segmentación de imágenes de cuencas hidrográficas:

  1. Preprocesamiento "Dam" de la imagen original: Dependiendo de la situación de la imagen, las características de los bordes de la imagen original se mejoran mediante máscaras;
  2. Etiquetado de los puntos de inyección de agua en cada cuenca: Eliminación de ruido de imagen -> Binarización -> Extracción de esqueleto mediante transformación de distancia -> Normalización -> Binarización para extraer el centro de la cuenca -> Búsqueda de contorno -> Relleno de píxeles para marcar los puntos de inyección de agua;
  3. Realice cambios de cuencas hidrográficas en imágenes preprocesadas con características obvias de "presa" e imágenes con puntos de agua anotados;
  4. Color de relleno de la imagen de salida, visualización.
    Insertar descripción de la imagen aquí

API:

public static void Watershed(InputArray image, InputOutputArray markers);

InputArray: imagen con características obvias de "presa" después del preprocesamiento;
InputOutputArray: mapa de etiquetado de puntos de inyección de agua

Pasos clave: marcado del punto de inyección de agua
Insertar descripción de la imagen aquí

Demostración de código:

if (fileDialog.ShowDialog() == DialogResult.OK)
{
    
    
    picFile = fileDialog.FileName;

    //展示图
    Mat displayImg = Cv2.ImRead(picFile);

    //均值滤波,降噪
    Cv2.Blur(displayImg, displayImg, new OpenCvSharp.Size(3, 3), new Point(-1, -1));

    //标记图
    Mat srcMarkerImg = new Mat(picFile, ImreadModes.Grayscale);

    //均值滤波,降噪
    Cv2.Blur(srcMarkerImg, srcMarkerImg, new OpenCvSharp.Size(3, 3), new Point(-1, -1));

    Cv2.Threshold(srcMarkerImg, srcMarkerImg, 93, 255, ThresholdTypes.BinaryInv);

    var kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(12, 12));

    //闭运算,去除图像中的小黑点
    Cv2.MorphologyEx(srcMarkerImg, srcMarkerImg, MorphTypes.Close, kernel);

    Mat distanceImg = new Mat();
    //距离变换
    Cv2.DistanceTransform(srcMarkerImg, distanceImg, DistanceTypes.L1, DistanceTransformMasks.Mask3, 5);

    //归一化
    Cv2.Normalize(distanceImg, distanceImg, 0, 1.0, NormTypes.MinMax);


    //二值化
    Cv2.Threshold(distanceImg, distanceImg, 0.5, 1, ThresholdTypes.Binary);

    distanceImg.ConvertTo(distanceImg, MatType.CV_8UC1);

    //标记结果,即前景色图像
    Mat markers = Mat.Zeros(srcMarkerImg.Size(), MatType.CV_32SC1);

    //找轮廓轮廓
    Cv2.FindContours(distanceImg, out OpenCvSharp.Point[][] contours, out HierarchyIndex[] outputArray, RetrievalModes.External, ContourApproximationModes.ApproxSimple);

    for (int i = 0; i < contours.Length; i++)
           {
    
    
               //对各个标记区域填充不同的像素值,后阶段根据像素值区分区域
               Cv2.DrawContours(markers, contours, (int)i, new Scalar((int)i + 1), -1);
           }

    //标记背景
    Cv2.Circle(markers, new Point(15, 15), 10, new Scalar(255), -1);


    Mat displayMakers = new Mat();
    markers.ConvertTo(displayMakers, MatType.CV_8UC1);
    picBox_Process.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(displayMakers * 100);


    displayImg.ConvertTo(displayImg, MatType.CV_8UC3);

    //分水岭操作
    Cv2.Watershed(displayImg, markers);

    //生成随机颜色数组
    Vec3b[] colors = new Vec3b[contours.Length];
    Random rB = new Random();
    Random rG = new Random();
    Random rR = new Random();
    for (int i = 0; i < contours.Length; i++)
           {
    
    
               var B = rB.Next(50, 98);
               var G = rG.Next(47, 255);
               var R = rR.Next(56, 120);

               RNG rngB = new RNG((ulong)B);
               RNG rngG = new RNG((ulong)G);
               RNG rngR = new RNG((ulong)R);

               colors[i] = new Vec3b((byte)rngB.Uniform(0, 255), (byte)rngG.Uniform(0, 255), (byte)rngR.Uniform(0, 255));
               Thread.Sleep(200);
           }

    //输出图像
    Mat resultImg = Mat.Zeros(markers.Size(), MatType.CV_8UC3);

    for (int i = 0; i < markers.Rows; i++)
           {
    
    
               for (int j = 0; j < markers.Cols; j++)
                    {
    
    
                        int index = markers.At<int>(i, j);
                        if (index > 0 && index <= contours.Length)
                        {
    
    
                            resultImg.At<Vec3b>(i, j) = colors[index - 1];
                        }
                        else
                        {
    
    
                            //填充背景为蓝色
                            resultImg.At<Vec3b>(i, j) = new Vec3b(255, 0, 0);
                        }
                    }
           }

    
    //同原图相加
    Cv2.Absdiff(displayImg, resultImg, resultImg);
    picBox_After.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(resultImg);

    picBox_Display.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(displayImg);
}

Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_40671962/article/details/128056798
Recomendado
Clasificación