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; } /// 后部声学特征 :
}
}