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實際是每個像素選取的最大值所屬的圖像編號。
比如這樣的:

1 2
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#的這方面代碼還沒有,希望對大家有一定的價值!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM