用opencvsharp加载分割模型后处理操作

用opencvsharp加载分割模型后处理操作?

 // Mat score = netmodel.forward();
cv::Mat dnn_argmax(const Mat& score)
{
    const int rows = score.size[2];
    const int cols = score.size[3];
    const int chns = score.size[1];
    Mat maxCl = Mat::zeros(rows, cols, CV_8UC1);
    Mat maxVal(rows, cols, CV_32FC1, score.data);
    cout << maxVal.channels()<< endl;
    for (int ch = 1; ch < chns; ch++) {
        //遍历row 行
        for (int row = 0; row < rows; row++) {
            //--获取行指针加速内存操作
            const float* ptrScore = score.ptr<float>(0, ch, row);
            uint8_t* ptrMaxCl = maxCl.ptr<uint8_t>(row);
            float* ptrMaxVal = maxVal.ptr<float>(row);
            //遍历col 列
            for (int col = 0; col < cols; col++) {
                if (ptrScore[col] > ptrMaxVal[col]) {
                    ptrMaxVal[col] = ptrScore[col];
                    ptrMaxCl[col] = (uchar)ch;
                }
            }
        }
    }
    Mat seg2(rows, cols, CV_8UC1);
    for (int row = 0; row < rows; row++) {
        const uchar* ptrMaxCl = maxCl.ptr<uchar>(row);
        uchar* ptrSeg2 = seg2.ptr<uchar>(row);
        for (int col = 0; col < cols; col++) {
            ptrSeg2[col] = ptrMaxCl[col];
        }
    }
    return seg2;
}

c++ 实现了,请问C#如何实现分割网络的后处理?包括统计指定类别像素个数的操作

在使用OpenCVSharp加载分割模型后,可以使用以下代码进行后处理操作:

  1. 首先,使用OpenCVSharp加载模型并进行推理,得到分割结果:
Net netModel = CvDnn.ReadNetFromTensorflow("path/to/model.pb", "path/to/model.pbtxt");

Mat inputBlob = CvDnn.BlobFromImage(image, scalefactor, size, mean, swapRB, crop);
netModel.SetInput(inputBlob, "input");

Mat score = netModel.Forward();
  1. 然后,使用OpenCV的argmax函数找到每个像素点的类别(即分割结果的最大值所在的通道):
Mat argmax = new Mat(score.Size(), MatType.CV_8UC1);
IntPtr[] argmaxPtrs = new IntPtr[argmax.Rows];
for (int i = 0; i < argmax.Rows; ++i)
    argmaxPtrs[i] = argmax.Row(i).Data;

int channelCount = score.Size().Height;
int channelSize = score.Size().Width;

for (int i = 0; i < argmax.Rows; ++i)
{
    for (int j = 0; j < argmax.Cols; ++j)
    {
        int maxId = 0;
        float maxVal = score.At<float>(i, j, 0);
        for (int c = 1; c < channelCount; ++c)
        {
            float val = score.At<float>(i, j, c);
            if (val > maxVal)
            {
                maxVal = val;
                maxId = c;
            }
        }
        argmaxPtrs[i].SetValue((byte)maxId, j);
    }
}
  1. 最后,可以根据argmax矩阵为每个类别指定一个颜色,并用颜色渲染分割结果:
Scalar[] colorMap = new Scalar[] {
    new Scalar(0, 0, 0), // class 0 (background)
    new Scalar(0, 0, 255), // class 1 (red)
    new Scalar(0, 255, 0), // class 2 (green)
    new Scalar(255, 0, 0) // class 3 (blue)
};

Mat output = new Mat(image.Size(), image.Type());
for (int i = 0; i < argmax.Rows; ++i)
{
    for (int j = 0; j < argmax.Cols; ++j)
    {
        byte classId = argmax.At<byte>(i, j);
        Scalar color = colorMap[classId];
        output.Set(i, j, color);
    }
}

Cv2.ImShow("Segmentation Result", output);
Cv2.WaitKey(0);

这样,就可以使用OpenCVSharp加载分割模型并进行后处理操作。

基于OpenCvSharp的数字图像处理 - 图像分割_opencvsharp 切割图片_还是叫明的博客-CSDN博客 图像分割是根据图像中各部分的特征,分割出不同的区域,这些区域可能代表了不同的物体。最简单的图像分割是区分出背景和前景。图像分割目前有一些比较成熟的技术,但想不通过一些辅助手段而达到比较好的分割效果,还是有一定难度的。一、漫水填充如果用过Photoshop的读者,应该对这项功能很熟悉。先设定一个阈值,然后在图像中的某个区域点一下鼠标,类似这个区域的像素都会被填充为某一颜色。这项功能需要我们指..._opencvsharp 切割图片 https://blog.csdn.net/lweiyue/article/details/105953206?ops_request_misc=&request_id=&biz_id=102&utm_term=%E7%94%A8opencvsharp%E5%8A%A0%E8%BD%BD%E5%88%86%E5%89%B2%E6%A8%A1%E5%9E%8B%E5%90%8E%E5%A4%84%E7%90%86%E6%93%8D%E4%BD%9C%EF%BC%9F&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-105953206.142^v92^controlT0_1&spm=1018.2226.3001.4187&ydreferer=aHR0cHM6Ly9zby5jc2RuLm5ldC9zby9zZWFyY2g%2FcT0lRTclOTQlQThvcGVuY3ZzaGFycCVFNSU4QSVBMCVFOCVCRCVCRCVFNSU4OCU4NiVFNSU4OSVCMiVFNiVBOCVBMSVFNSU5RSU4QiVFNSU5MCU4RSVFNSVBNCU4NCVFNyU5MCU4NiVFNiU5MyU4RCVFNCVCRCU5QyVFRiVCQyU5RiZ0PSZ1PSZ1cnc9

【相关推荐】



  • 帮你找了个相似的问题, 你可以看下: https://ask.csdn.net/questions/7711448
  • 你也可以参考下这篇文章:基于OpenCvSharp的数字图像处理 - 像素操作
  • 除此之外, 这篇博客: 用opencvSharp实现在任意多边形内寻找最大的内接正交矩形中的 用opencvSharp实现在任意多边形内寻找最大的内接正交矩形 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:

    之前写过一篇在任意多边形内寻找近似最大的内接正交矩形,但不怎么符合工作要求,于是再认真看了看之前

    那篇文章,最后总算是搞出来了。
    原图:
    在这里插入图片描述
    结果:
    在这里插入图片描述

    1.第一步还是先求出多边形的近似轮廓,减少轮廓数量,方便后面计算。

    2.根据轮廓让点与下一个点之间形成一个矩形,然后让每个矩形都与当前所有矩形相交,求出相交的矩形,再把这些矩形所有的角放到一个集合里。
    在这里插入图片描述
    3.最后去除重复的点,再让这些点两两组合成一个矩形,判断是否为内部矩形,如果是就算出面积,找出最大内接矩形。
    在这里插入图片描述
    比如一共4个点,第1个与第2个形成矩形(矩形1),第1与第3(矩形2),第1与第4(矩形3),第2与第3(矩形4),第2与第4(矩形5),第3与第4(矩形6);
    由于矩形1为第一个元素,没有相交矩形,所以直接放入allPoint中;
    接着把矩形2的四个角,以及矩形2和矩形1相交矩形的四个角,放入allPoint中;
    矩形3以此类推,其本身四个角,以及和矩形1相交矩形的四个角,以及和矩形2相交矩形的四个角,放入allPoint中。

    以上就是所有步骤了,代码实现起来还是比较简单的,但是这个方法的原理理解起来就比较困难了,看了半天也看不到原理。
    完整代码:

            public Form1()
            {
                InitializeComponent();
                Test();
            }
                    
            private static void Test()
            {
                var src = Cv2.ImRead("C:\\Users\\Administrator\\Desktop\\test.png", ImreadModes.Color);
                var dst = new Mat();
                Cv2.CvtColor(src, dst, ColorConversionCodes.RGB2GRAY);
                Cv2.FindContours(dst, out var contours, out var hierarchy, RetrievalModes.External,
                    ContourApproximationModes.ApproxSimple);
                List<List<Point>> approxContours = new List<List<Point>>();
                for (int i = 0; i < contours.Length; i++)
                {
                    //先求出多边形的近似轮廓,减少轮廓数量,方便后面计算
                    var approxContour = Cv2.ApproxPolyDP(contours[i], 20, true);
                    approxContours.Add(approxContour.ToList());
                    DrawContour(src, approxContour, Scalar.White, 1);
                }
    
                foreach (var contour in approxContours)
                {
                    GetMaxInscribedRect(src, contour);
                }
    
                Cv2.ImShow("src", src);
            }
    
            private static Rect GetMaxInscribedRect(Mat src, List<Point> contour)
            {
                //根据轮廓让点与下一个点之间形成一个矩形,然后让每个矩形都与当前所有矩形相交,求出相交的矩形,
                //再把这些矩形所有的角放到一个集合里,筛选出在轮廓内并且非重复的点,
                //最后让这些点两两组合成一个矩形,判断是否为内部矩形,算出面积,找出最大内接矩形。
                //比如一共4个点,第1个与第2个形成矩形(矩形1),第1与第3(矩形2),
                //第1与第4(矩形3),第2与第3(矩形4),第2与第4(矩形5),第3与第4(矩形6),
                //由于矩形1为第一个元素,没有相交矩形,所以直接放入allPoint中,
                //接着把矩形2的四个角,以及矩形2和矩形1相交矩形的四个角,放入allPoint中,
                //矩形3以此类推,其本身四个角,以及和矩形1相交矩形的四个角,以及和矩形2相交矩形的四个角
                Rect maxInscribedRect = new Rect();
                List<Rect> allRect = new List<Rect>();
                List<Point> allPoint = new List<Point>(contour);
    
                //根据轮廓让点与下一个点之间形成一个矩形
                for (int i = 0; i < contour.Count; i++)
                {
                    for (int j = i + 1; j < contour.Count; j++)
                    {
                        var p1 = contour[i];
                        var p2 = contour[j];
                        if (p1.Y == p2.Y || p1.X == p2.X)
                            continue;
                        var tempRect = FromTowPoint(p1, p2);
                        allPoint.AddRange(GetAllCorner(tempRect));
                        //让每个矩形都与当前所有矩形相交,求出相交的矩形,再把这些矩形所有的角放到一个集合里
                        foreach (var rect in allRect)
                        {
                            var intersectR = tempRect.Intersect(rect);
                            if (intersectR != Rect.Empty)
                                allPoint.AddRange(GetAllCorner(intersectR));
                        }
    
                        allRect.Add(tempRect);
                    }
                }
    
                //去除重复的点,再让这些点两两组合成一个矩形,判断是否为内部矩形,算出面积,找出最大内接矩形
                List<Point> distinctPoints = allPoint.Distinct().ToList();
                for (int i = 0; i < distinctPoints.Count; i++)
                {
                    for (int j = i + 1; j < distinctPoints.Count; j++)
                    {
                        var tempRect = FromTowPoint(distinctPoints[i], distinctPoints[j]);
                        //只要矩形包含一个轮廓内的点,就不算多边形的内部矩形;只要轮廓不包含该矩形,该矩形就不算多边形的内部矩形
                        if (!ContainPoints(contour, GetAllCorner(tempRect)) || ContainsAnyPt(tempRect, contour))
                            continue;
                        src.Rectangle(tempRect, Scalar.RandomColor(), 2);
                        if (tempRect.Width * tempRect.Height > maxInscribedRect.Width * maxInscribedRect.Height)
                            maxInscribedRect = tempRect;
                    }
                }
    
                src.Rectangle(maxInscribedRect, Scalar.Yellow, 2);
                return maxInscribedRect == Rect.Empty ? Cv2.BoundingRect(contour) : maxInscribedRect;
            }
    
            public static Point[] GetAllCorner(Rect rect)
            {
                Point[] result = new Point[4];
                result[0] = rect.Location;
                result[1] = new Point(rect.X + rect.Width, rect.Y);
                result[2] = rect.BottomRight;
                result[3] = new Point(rect.X, rect.Y + rect.Height);
                return result;
            }
    
            public static bool ContainPoint(List<Point> contour, Point p1)
            {
                return Cv2.PointPolygonTest(contour, p1, false) > 0;
            }
    
            public static bool ContainPoints(List<Point> contour, IEnumerable<Point> points)
            {
                foreach (var point in points)
                {
                    if (Cv2.PointPolygonTest(contour, point, false) < 0)
                        return false;
                }
                return true;
            } 
    
            private static void DrawContour(Mat mat, Point[] contour, Scalar color, int thickness)
            {
                for (int i = 0; i < contour.Length; i++)
                {
                    if (i + 1 < contour.Length)
                        Cv2.Line(mat, contour[i], contour[i + 1], color, thickness);
                }
            }
    
            /// <summary>
            /// 是否有任意一个点集合中的点包含在矩形内,在矩形边界上不算包含
            /// </summary>
            /// <param name="rect"></param>
            /// <param name="points"></param>
            /// <returns></returns>
            private static bool ContainsAnyPt(Rect rect, IEnumerable<Point> points)
            {
                foreach (var point in points)
                {
                    if (point.X > rect.X && point.X < rect.X + rect.Width && point.Y < rect.BottomRight.Y && point.Y > rect.Y)
                        return true;
                }
                return false;
            }
    
            /// <summary>
            /// 用任意两点组成一个矩形
            /// </summary>
            /// <param name="p1"></param>
            /// <param name="p2"></param>
            /// <returns></returns>
            public static Rect FromTowPoint(Point p1, Point p2)
            {
                if (p1.X == p2.X || p1.Y == p2.Y)
                    return Rect.Empty;
    
                if (p1.X > p2.X && p1.Y < p2.Y)
                {
                    (p1, p2) = (p2, p1);
                }
                else if (p1.X > p2.X && p1.Y > p2.Y)
                {
                    (p1.X, p2.X) = (p2.X, p1.X);
                }
                else if (p1.X < p2.X && p1.Y < p2.Y)
                {
                    (p1.Y, p2.Y) = (p2.Y, p1.Y);
                }
                return Rect.FromLTRB(p1.X, p2.Y, p2.X, p1.Y);
            }
    

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^


```c#
using OpenCvSharp;

public static Mat DnnArgMax(Mat score)
{
    int rows = score.Size[2];
    int cols = score.Size[3];
    int chns = score.Size[1];
    Mat maxCl = Mat.Zeros(rows, cols, MatType.CV_8UC1);
    Mat maxVal = new Mat(rows, cols, MatType.CV_32FC1, score.Data);
    Console.WriteLine(maxVal.Channels());
    
    for (int ch = 1; ch < chns; ch++)
    {
        for (int row = 0; row < rows; row++)
        {
            float[] ptrScore = new float[cols];
            byte[] ptrMaxCl = new byte[cols];
            float[] ptrMaxVal = new float[cols];
            Cv2.GetRow(score, row, ch, ptrScore);
            Cv2.GetRow(maxCl, row, ptrMaxCl);
            Cv2.GetRow(maxVal, row, ptrMaxVal);
            
            for (int col = 0; col < cols; col++)
            {
                if (ptrScore[col] > ptrMaxVal[col])
                {
                    ptrMaxVal[col] = ptrScore[col];
                    ptrMaxCl[col] = (byte)ch;
                }
            }
            Cv2.SetRow(maxCl, row, ptrMaxCl);
            Cv2.SetRow(maxVal, row, ptrMaxVal);
        }
    }
    
    Mat seg2 = new Mat(rows, cols, MatType.CV_8UC1);
    for (int row = 0; row < rows; row++)
    {
        byte[] ptrMaxCl = new byte[cols];
        byte[] ptrSeg2 = new byte[cols];
        Cv2.GetRow(maxCl, row, ptrMaxCl);
        Cv2.GetRow(seg2, row, ptrSeg2);
        
        for (int col = 0; col < cols; col++)
        {
            ptrSeg2[col] = ptrMaxCl[col];
        }
        Cv2.SetRow(seg2, row, ptrSeg2);
    }
    return seg2;
}


```

以下回答来自AI:
以下是将上述C++代码转换为C#代码的示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;

namespace OpenCvSharpExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Load the score image
            Mat score = Cv2.ImRead("score.jpg");

            // Perform the DNN argmax operation
            Mat dnn_argmax = Dnn.ArgMax(score);

            // Convert the output to a binary image
            Mat seg2 = new Mat();
            Cv2.Threshold(dnn_argmax, seg2, 0, 255, ThresholdTypes.Binary);

            // Display the result
            Cv2.ImShow("Result", seg2);
            Cv2.WaitKey(0);
        }
    }
}

需要注意的是,上述C#代码中使用了OpenCvSharp库的C#封装,因此需要在代码文件的顶部添加以下引用:

using OpenCvSharp;

此外,还需要在代码文件所在的项目中添加对OpenCvSharp.dll的引用。可以在Visual Studio中右键单击项目,选择“管理NuGet程序包”,在搜索框中输入“OpenCvSharp”,然后点击“安装”按钮即可。


 
 
```c#
using OpenCvSharp;
 
public static Mat DnnArgMax(Mat score)
{
    int rows = score.Size[2];
    int cols = score.Size[3];
    int chns = score.Size[1];
    Mat maxCl = Mat.Zeros(rows, cols, MatType.CV_8UC1);
    Mat maxVal = new Mat(rows, cols, MatType.CV_32FC1, score.Data);
    Console.WriteLine(maxVal.Channels());
    
    for (int ch = 1; ch < chns; ch++)
    {
        for (int row = 0; row < rows; row++)
        {
            float[] ptrScore = new float[cols];
            byte[] ptrMaxCl = new byte[cols];
            float[] ptrMaxVal = new float[cols];
            Cv2.GetRow(score, row, ch, ptrScore);
            Cv2.GetRow(maxCl, row, ptrMaxCl);
            Cv2.GetRow(maxVal, row, ptrMaxVal);
            
            for (int col = 0; col < cols; col++)
            {
                if (ptrScore[col] > ptrMaxVal[col])
                {
                    ptrMaxVal[col] = ptrScore[col];
                    ptrMaxCl[col] = (byte)ch;
                }
            }
            Cv2.SetRow(maxCl, row, ptrMaxCl);
            Cv2.SetRow(maxVal, row, ptrMaxVal);
        }
    }
    
    Mat seg2 = new Mat(rows, cols, MatType.CV_8UC1);
    for (int row = 0; row < rows; row++)
    {
        byte[] ptrMaxCl = new byte[cols];
        byte[] ptrSeg2 = new byte[cols];
        Cv2.GetRow(maxCl, row, ptrMaxCl);
        Cv2.GetRow(seg2, row, ptrSeg2);
        
        for (int col = 0; col < cols; col++)
        {
            ptrSeg2[col] = ptrMaxCl[col];
        }
        Cv2.SetRow(seg2, row, ptrSeg2);
    }
    return seg2;
}
 
 

基于OpenCvSharp图像分割提取目标区域和定位
可以参考下


OpenCVsharp GrabCut图像分割_opencvsharp 自动裁剪_GS557的博客-CSDN博客 OpenCVsharp GrabCut图像分割_opencvsharp 自动裁剪 https://blog.csdn.net/GS557/article/details/126400218