• OpenCVSharp 景深融合


    C#景深融合

    最近因为一个项目要求,将matlab写的一些关于图像的算法转成C#。这个挺坑爹的,C#处理图像还是挺少的,opencv关于这方面的资源挺少的。我用的是opencvsharp这个第三方库,GitHub上有资源。
    这个景深融合其实是一个显微镜扫描成像的问题,一共有数张图像,都是局部清晰,其它部分模糊。比如下面这样:
    在这里插入图片描述

    在这里插入图片描述
    实际处理思路是:图像边缘检测,然后做了一个平滑处理,根据灰度图的亮度进行筛选,形成一个分区。最后根据分区处理像素的填充。
    下面贴代码:
    读取图片的操作就略去了,边缘提取用的是sobel,注意一下,opencvsharp中的图像处理注意mat数据的溢出。及时调整mat的像素深度比如16s,通常原始图像读取是8u。像素深度关系到具体坐标的数据格式。

     1     class Oper
     2     {
     3         public static Mat Deal(Mat ImIn)
     4         {
     5             Mat mat_gray = new Mat();
     6             //
     7             //Mat smooth_img = new Mat();
     8             //Cv2.GaussianBlur(ImIn, smooth_img, new OpenCvSharp.Size(3, 3), 0.96, 0.96, BorderTypes.Default);
     9             //灰度图
    10 
    11 
    12             Cv2.CvtColor(ImIn, mat_gray, ColorConversionCodes.BGR2GRAY);
    13             //GetMatData.Arr(mat_gray);
    14 
    15             Mat X = new Mat(); Mat Y = new Mat();
    16             //InputArray arr = InputArray.Create<float>(new float[3, 3] { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } });
    17             //Cv2.Filter2D(mat_gray,X , -1, arr, new Point(-1, -1), 0);
    18             //InputArray arr_convert = InputArray.Create<float>(new float[3, 3] { { -1, 0, -1 }, { -2, 0, 2 }, { -1, 0, 1 } });
    19             //Cv2.Filter2D(mat_gray, Y, -1, arr, new Point(-1, -1), 0);
    20             
    21             
    22             //sobel边缘
    23             //-----------这里开始转变为16位运算-------------
    24             Cv2.Sobel(mat_gray, X, MatType.CV_16S, 1, 0, 3,1,0,BorderTypes.Replicate);
    25             Cv2.Sobel(mat_gray, Y, MatType.CV_16S, 0, 1, 3,1,0,BorderTypes.Replicate);
    26             //GetMatData.getData(X); 
    27             //GetMatData.getData(Y);
    28 
    29             int width = X.Cols; int heigth = Y.Rows;
    30             //-------double型数据的对应像素深度是64F---------
    31             var output = new Mat(X.Size(),MatType.CV_64F);
    32 
    33             var indexer_x = X.GetGenericIndexer<Int16>();
    34             var indexer_y = Y.GetGenericIndexer<Int16>();
    35             var indexer_op = output.GetGenericIndexer<double>();
    36             //算术平均
    37             for (int index = 0; index < heigth ; index++)
    38             {
    39                 for (int index_y = 0; index_y < width; index_y++)
    40                 {
    41                     Int16 Gx = indexer_x[index,index_y];
    42                     Int16 Gy = indexer_y[index,index_y];
    43 
    44                     double v1 = Math.Pow(Gx, 2);
    45                     double v2 = Math.Pow(Gy, 2);
    46                     double val = Math.Sqrt(v1 + v2);
    47 
    48                     indexer_op[index, index_y] = val;
    49                 }
    50             }
    51             //var ss =indexer_op[0, 0];
    52 
    53             Cv2.GaussianBlur(output,output,new OpenCvSharp.Size(31,31),11);
    54             //Cv2.ImShow("te", output); Cv2.WaitKey(0);
    55             return output;
    56         }
    57 
    58     }

    到这里基本完成了图像的局部提取,下面进行一下分区的对比提取。
    这部分我是这样理解的,比如十张局部扫描图,根据像素的梯度变化可以将清晰处与模糊处区分开来,sobel可以很好的将边缘提取出来,经过平滑处理形成分区。
    之后十张图相当于MN10 的矩阵,根据像素的梯度变化,每个像素取最大值可以准确提取这部分图像的清晰部分。(这里一个理解是实际上清晰部分的梯度变化较模糊处大,梯度值实际上可以表现为亮度的大小)
    像素对比处代码如下:

     1         public static Mat id_Mat (Mat[]coll)
     2         {
     3             int heigth = coll[0].Rows;
     4             int width = coll[0].Cols;
     5             
     6             Mat max_id = new Mat(coll[0].Size(),MatType.CV_8U);
     7             var indexer_id = max_id.GetGenericIndexer<byte>();
     8             //int ss = max_id.At<double>(10, 10);
     9             //
    10             
    11 
    12             //注意像素深度的设置,数据格式的统一
    13             Mat mat1 = coll[0];
    14             var indexer_pre=mat1.GetGenericIndexer<double>();
    15             for (int num = 1; num < coll.Length; num++)
    16             {
    17                 var mat2 = coll[num];
    18                 var indexer = mat2.GetGenericIndexer<double>();
    19                 for (int index = 0; index < heigth ; index++)
    20                 {
    21                     for (int index_y = 0; index_y < width; index_y++)
    22                     {
    23                         double G1 = indexer_pre[index,index_y];
    24                         double G2 = indexer[index, index_y];
    25                         if (G1 <= G2)
    26                         {
    27                             double G_double = (double)G2;
    28                             indexer_pre[index, index_y] = G_double;
    29                             indexer_id[index, index_y] = (byte)num;
    30                         }
    31                     }
    32                 }
    33             }
    34             return max_id;
    35         }

    一点说明,这里为了后续图像合成的方便,输出mat max_id实际是每个像素选取的最大值所属的图像编号。
    比如这样的:

    12
    1 2

    左上的像素取图片1中对应像素的值。

    最后就是填像素值合成了,如下:

     1     class Merge
     2     {   //ID点阵选择相应ID图像填色
     3         public static Mat ImMerge(Mat IDIm,Mat[]Coll_Ori)
     4         {
     5             Mat ImMer = new Mat(Coll_Ori[0].Size(), Coll_Ori[0].Type());
     6             var indexer_mer=ImMer.GetGenericIndexer<Vec3b>();
     7             var indexer_id = IDIm.GetGenericIndexer<byte>();
     8 
     9             int heigth = IDIm.Rows; int width = IDIm.Cols;
    10             for (int index=0;index<Coll_Ori.Length;index++)
    11             {
    12                 for (int x = 0; x < heigth; x++)
    13                 {
    14                     for (int y = 0; y < width; y++)
    15                     {
    16                         int val_ID = indexer_id[x, y];
    17                         if (val_ID == index) 
    18                         {
    19                             var Ori_indexer = Coll_Ori[index].GetGenericIndexer<Vec3b>();
    20                             indexer_mer[x, y] = Ori_indexer[x, y];
    21                         }
    22                         else { continue; }
    23                     }
    24                 }
    25             }
    26             return ImMer;
    27         }
    28     }

    最后的输出图像如下:
    例子1,图有点大,截个屏吧!
    例子1,实际图有点大,截个屏
    例子2
    例子2

    总的来说算法的处理效果是不错的,速度上也可以,毕竟C#还是不太适合做算法。我看网上基于C#的这方面代码还没有,希望对大家有一定的价值!

  • 相关阅读:
    Java开发常用Util工具类
    冒泡排序
    EMQ 消息服务器
    将jar文件包打成exe文件
    mina框架搭建tcp服务器:编写自定义协议及编解码器
    SpringBoot中定时任务的设置
    SpringBoot项目+Shiro(权限框架)+Redis(缓存)集成
    计算两个时间之间的天数
    关于extern的使用
    ADC采样间隔问题+TRGO作为ADC的触发源头
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/14214652.html
Copyright © 2020-2023  润新知