using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Drawing; using System.Windows.Media.Imaging; using System.Drawing.Imaging; using System.Runtime.InteropServices; namespace SegmentDescribDemo { /// /// 图像处理工具类 /// [StructLayout(LayoutKind.Sequential)] public struct MyPoint { public int x; public int y; } /// /// 病灶轮廓的纵、横轴的坐标点 /// public struct AxisPoint { public MyPoint horizontalPt1; // 病灶轮廓的 横轴(水平方向) 端点坐标 public MyPoint horizontalPt2; public MyPoint verticalPt1; // 病灶轮廓的 纵轴 端点坐标 public MyPoint verticalPt2; } public struct LesionDescri { public int shape; /// 形状描述。0未标注,1椭圆,2类圆,3不规则 public int orientation; /// 生长方向。0未标注,1平行,2非平行 public int echo; /// 回声类型。0未标注,1无回声,2低回声,3等回声,4高回声,5混合回声 public int boundary; /// 边界清晰度。0未标注,1清晰,2不清晰 public int margin; /// 边缘光整度。0未标注,1光整,不光整 public int calcification; /// 钙化。0未标注,1无钙化,2粗大钙化,3内部微钙化,外部微钙化 public AxisPoint axisPt; } public struct LesionDescriNow { public int shape; /// 形状描述。0未标注,1椭圆,2类圆,3不规则 public int orientation; /// 生长方向。0未标注,1平行,2非平行 public int echo; /// 回声类型。0未标注,1无回声,2低回声,3等回声,4高回声,5混合回声 public int boundary; /// 边界清晰度。0未标注,1清晰,2不清晰 public int margin; /// 边缘光整度。0未标注,1光整,不光整 public int calcification; /// 钙化。0未标注,1无钙化,2粗大钙化,3内部微钙化,外部微钙化 public int posteriorAcousticFeature; /// 后部声学特征 : } public static class ImageUtility { [DllImport(@"BreastLesionSeg.dll", CallingConvention = CallingConvention.Cdecl)] public static unsafe extern int ContourDetectBLS(byte[] img_data, int channels, int img_width, int img_height, roiCoor roi_vec, [In, Out] MyPoint[] contour_points); [DllImport(@"ActiveContourWithoutEdge_IO.dll", CallingConvention = CallingConvention.Cdecl)] public static unsafe extern int ContourDetectACWE(byte[] img_data, int channels, int img_width, int img_height, roiCoor roi_vec, [In, Out] MyPoint[] contour_points); [DllImport(@"ActiveContourDRLSE_IO.dll", EntryPoint = "ContourDetectDRLSE", CallingConvention = CallingConvention.Cdecl)] public static unsafe extern int ContourDetectDRLSE(byte[] img_data, int channels, int img_width, int img_height, roiCoor roi_vec, [In, Out] MyPoint[] contour_points); [DllImport(@"ActiveContourLocalBinaryFitting.dll", EntryPoint = "ContourDetectLBF", CallingConvention = CallingConvention.Cdecl)] public static unsafe extern int ContourDetectLBF(byte[] img_data, int channels, int img_width, int img_height, roiCoor roi_vec, [In, Out] MyPoint[] contour_points); [DllImport(@"LevelSetEvolutionWithoutReinitialization.dll", EntryPoint = "ContourDetectLSEWR", CallingConvention = CallingConvention.Cdecl)] public static unsafe extern int ContourDetectLSEWR(byte[] img_data, int channels, int img_width, int img_height, roiCoor roi_vec, [In, Out] MyPoint[] contour_points); [DllImport(@"FCM_IO.dll", CallingConvention = CallingConvention.Cdecl)] public static unsafe extern int ContourDetectFCM(byte[] img_data, int channels, float contrast_value, int img_width, int img_height, roiCoor roi_vec, [In, Out] MyPoint[] contour_points); [DllImport(@"LesionDescription.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void LoadModel(char[] shapePath); [DllImport(@"LesionDescription.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void BreastDescription(byte[] img_data, int channels, int img_w, int img_h, roiCoor roi_vec, int num_pts, MyPoint[] contour_points, AxisPoint axisPt, ref LesionDescriNow lesionDescr); [DllImport(@"LesionDescription.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void FreeModel(); public static BitmapImage BitmapToBitmapImage(Bitmap img) { BitmapImage bmpimg = new BitmapImage(); using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { img.Save(ms, ImageFormat.Png); bmpimg.BeginInit(); bmpimg.StreamSource = ms; bmpimg.CacheOption = BitmapCacheOption.OnLoad; bmpimg.EndInit(); bmpimg.Freeze(); ms.Dispose(); } return bmpimg; } public unsafe static PointF[] ContourDetect(SegDataInput data, EnumSegMethod segMethod) { if ((data.InputImage.PixelFormat != PixelFormat.Format24bppRgb) && (data.InputImage.PixelFormat != PixelFormat.Format8bppIndexed) && (data.InputImage.PixelFormat != PixelFormat.Format32bppRgb)) { return new PointF[0]; } if (data.InputRoi.Width * data.InputRoi.Height <= 0) { return new PointF[0]; } BitmapData bmData; int imgWidth = data.InputImage.Width; int imgHeight = data.InputImage.Height; int channels = (data.InputImage.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 1; Rectangle rect = new Rectangle(0, 0, imgWidth, imgHeight); bmData = data.InputImage.LockBits(rect, ImageLockMode.ReadOnly, data.InputImage.PixelFormat); byte[] imgData = new byte[imgWidth * imgHeight * channels]; var ptr0 = (byte*)bmData.Scan0.ToPointer(); int stride = bmData.Stride; for (int y = 0; y < imgHeight; y++) { for (int x = 0; x < imgWidth; x++) { for (int c = 0; c < channels; c++) // 通道数 { imgData[y * imgWidth * channels + x * channels + c] = ptr0[y * stride + x * channels + c]; } } } int max_num = data.InputRoi.Height * data.InputRoi.Width; MyPoint[] contourPts_tmp = new MyPoint[max_num]; roiCoor roi; roi.x = data.InputRoi.X; roi.y = data.InputRoi.Y; roi.width = data.InputRoi.Width; roi.height = data.InputRoi.Height; int ptsNum = 0; if (segMethod == EnumSegMethod.BLS) { ptsNum = ContourDetectBLS(imgData, channels, imgWidth, imgHeight, roi, contourPts_tmp); } if (segMethod == EnumSegMethod.FCM) { ptsNum = ContourDetectFCM(imgData, channels, 120, imgWidth, imgHeight, roi, contourPts_tmp); } if (segMethod == EnumSegMethod.ACWE) { ptsNum = ContourDetectACWE(imgData, channels, imgWidth, imgHeight, roi, contourPts_tmp); } if (segMethod == EnumSegMethod.DRLSE) { ptsNum = ContourDetectDRLSE(imgData, channels, imgWidth, imgHeight, roi, contourPts_tmp); } if (segMethod == EnumSegMethod.LBF) { ptsNum = ContourDetectLBF(imgData, channels, imgWidth, imgHeight, roi, contourPts_tmp); } if (segMethod == EnumSegMethod.LSEWR) { ptsNum = ContourDetectLSEWR(imgData, channels, imgWidth, imgHeight, roi, contourPts_tmp); } data.InputImage.UnlockBits(bmData); if (ptsNum <= 0) { return new PointF[0]; } Point[] contourPts = new Point[ptsNum]; for (int i = 0; i < ptsNum; i++) { contourPts[i].X = contourPts_tmp[i].x; contourPts[i].Y = contourPts_tmp[i].y; } PointF[] contour_points = new PointF[ptsNum]; for (int i = 0; i < ptsNum; i++) { contour_points[i] = new PointF(contourPts[i].X, contourPts[i].Y); } return contour_points; } public unsafe static LesionDescriptionResult BreastDescription(DesDataInput data, AxisPoint axisPt) { System.Drawing.PointF[] contours = data.Contour; LesionDescriptionResult result = null; // 病灶轮廓描述 int pts_num = contours.GetLength(0); int imgWidth = data.InputImage.Width; int imgHeight = data.InputImage.Height; MyPoint[] contourPts_tmp = new MyPoint[pts_num]; for (int i = 0; i < pts_num; i++) { contourPts_tmp[i].x = (int)contours[i].X; contourPts_tmp[i].y = (int)contours[i].Y; } int channels = (data.InputImage.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb) ? 3 : 1; BitmapData bmData; System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, imgWidth, imgHeight); bmData = data.InputImage.LockBits(rect, ImageLockMode.ReadOnly, data.InputImage.PixelFormat); byte[] img_data = new byte[imgWidth * imgHeight * channels]; var ptr0 = (byte*)bmData.Scan0.ToPointer(); int stride = bmData.Stride; for (int y = 0; y < imgHeight; y++) { for (int x = 0; x < imgWidth; x++) { for (int c = 0; c < channels; c++) { img_data[y * imgWidth * channels + x * channels + c] = ptr0[y * stride + x * channels + c]; } } } roiCoor roi; roi.x = data.InputRoi.X; roi.y = data.InputRoi.Y; roi.width = data.InputRoi.Width; roi.height = data.InputRoi.Height; LesionDescriNow lesionDescr = new LesionDescriNow(); lesionDescr.boundary = 0; lesionDescr.margin = 0; lesionDescr.echo = 0; lesionDescr.calcification = 0; lesionDescr.orientation = 0; AxisPoint axisPtNew = new AxisPoint(); axisPtNew.horizontalPt1 = new MyPoint { x = 0, y = 0 }; axisPtNew.horizontalPt2 = new MyPoint { x = 0, y = 0 }; axisPtNew.verticalPt1 = new MyPoint { x = 0, y = 0 }; axisPtNew.verticalPt2 = new MyPoint { x = 0, y = 0 }; if( true/*axisPt*/ ) { axisPtNew.horizontalPt1 = axisPt.horizontalPt1; axisPtNew.horizontalPt2 = axisPt.horizontalPt2; axisPtNew.verticalPt1 = axisPt.verticalPt1; axisPtNew.verticalPt2 = axisPt.verticalPt2; } int startTime2 = Environment.TickCount; BreastDescription(img_data, channels, imgWidth, imgHeight, roi, pts_num, contourPts_tmp, axisPtNew, ref lesionDescr); int endTime2 = Environment.TickCount; Console.WriteLine("TestTime:" + (endTime2 - startTime2) + "ms"); result = new LesionDescriptionResult(lesionDescr.shape, lesionDescr.orientation, lesionDescr.echo, lesionDescr.boundary, lesionDescr.margin, lesionDescr.calcification, lesionDescr.posteriorAcousticFeature ); return result; } public static void Init() { string shapePath = "../TrainModel/shape66.xml"; int startTime1 = Environment.TickCount; LoadModel(shapePath.ToCharArray()); int endTime1 = Environment.TickCount; Console.WriteLine("LoadTime:" + (endTime1 - startTime1) + "ms"); } public static void Dispose() { // DisposeModel //FreeModel(); } } /// /// 分割选用的方法 /// public enum EnumSegMethod { FCM, ACWE, DRLSE, LBF, LSEWR, BLS, //最新的分割算法 } /// /// 分割的输入数据 /// public class SegDataInput { /// /// 输入图像 /// public Bitmap InputImage { get; set; } = null; /// /// 感兴趣区域 /// public Rectangle InputRoi { get; set; } = Rectangle.Empty; /// /// 构造函数 /// /// /// public SegDataInput(Bitmap img, Rectangle rect) { InputImage = (Bitmap)img.Clone(); InputRoi = rect; } public void Dispose() { InputImage?.Dispose(); } } /// /// 描述的输入数据 /// public class DesDataInput { /// /// 输入图像 /// public Bitmap InputImage { get; set; } = null; /// /// 感兴趣区域 /// public Rectangle InputRoi { get; set; } = Rectangle.Empty; /// /// 病灶轮廓 /// public PointF[] Contour { get; set; } = null; public DesDataInput(Bitmap img, Rectangle rect, PointF[] contour) { InputImage = (Bitmap)img.Clone(); InputRoi = rect; Contour = contour; } public void Dispose() { InputImage?.Dispose(); } } /// /// 病灶描述结果 /// public class LesionDescriptionResult { public LesionDescriptionResult(int shape, int orientation, int echo, int boundary, int margin, int calcification, int posteriorAcousticFeature) { Shape = shape; Orientation = orientation; Echo = echo; Boundary = boundary; Margin = margin; Calcification = calcification; PosteriorAcousticFeature = posteriorAcousticFeature; } public bool Succeed { get; private set; } public int Shape { get; private set; } public int Orientation { get; private set; } public int Echo { get; private set; } public int Boundary { get; private set; } public int Margin { get; private set; } public int Calcification { get; private set; } public int PosteriorAcousticFeature { get; private set; } /// 后部声学特征 : } }