123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Runtime.InteropServices;
- using System.IO;
- namespace VideoStatusInspectorCSLib
- {
- public enum CurrentVideoState
- {
- Notjudged = 0, //不能判断当前状态
- Stationary = 1, //静止状态
- Moving = 2, //运行状态
- Error = 3, //存在错误
- };
- public struct ImageDataStructCS
- {
- public int ImgWidth;
- public int ImgHeight;
- public EnumColorType ImgColorType;
- }
- [StructLayout(LayoutKind.Sequential)]
- public struct ExtendStateCS
- {
- [MarshalAs(UnmanagedType.I1)]
- public bool LastState; //上一帧状态 false:静止 true :运行
- [MarshalAs(UnmanagedType.I1)]
- public bool MovingExtendedState; // true: 实际已经判为静置,但强制改为是扫查中的状态
- public int MovingExtendedNum; // 实际已经判为静置,但强制改为是扫查中的帧数
- public int TrueMovingNum; // 真正的扫查中的帧数(强制改成的扫查中的,不算)
- [MarshalAs(UnmanagedType.I1)]
- public bool StationaryExtendedState; // true: 实际已经判为扫查中,但强制改为是静置的状态
- public int StationaryExtendedNum; // 实际已经判为扫查中,但强制改为是静置状态的帧数
- public int TrueStationaryNum; // 真正的静置中的帧数(强制改为静置的,不算)
- };
- public class VideoStatusInspect
- {
- [DllImport(@"VideoStatusInspector", CallingConvention = CallingConvention.Cdecl)]
- [return: MarshalAs(UnmanagedType.I1)]
- internal static extern bool ConvertImage(IntPtr srcImgData, int imgwidth, int imgheight, EnumColorType colorType,
- int newW, int newH, IntPtr dstImgData);
- [DllImport(@"VideoStatusInspector")]
- [return: MarshalAs(UnmanagedType.I1)]
- internal static extern bool ProcessOneImage(IntPtr imgData, int imgwidth, int imgheight, EnumColorType colorType, ref double cannyRatio);
- [DllImport(@"VideoStatusInspector")]
- internal static extern double CompareTwoImage(IntPtr pSrc1, IntPtr pSrc2, int width, int height, int widthstep,
- ref double corr, ref double diff);
- [DllImport(@"VideoStatusInspector", CallingConvention = CallingConvention.Cdecl)]
- internal static extern CurrentVideoState JudgeImage(double[] diffData, double[] corrData, double[] cannyData,
- int num, int movingDelayNum, int stationaryDelayNum, int movingDelayTriggerFrames, int stationaryDelayTriggerFrames, bool manuallyUnfreeze,
- [MarshalAs(UnmanagedType.Struct)] ref ExtendStateCS state);
- private ExtendStateCS m_state;
- private ImageDataStructCS m_LastImg; //上一张图像信息
- private int m_queueSize = 30;
- private int m_movingDelayFrames = 90; // 从moving变为静置的时候,有多少帧被强制转为moving
- private int m_stationaryDelayFrames = 5; // 从静置变为moving的时候,有多少帧被强制转为静置
- private int m_movingDelayTriggerFrames = 10; // 从moving变为静置时,可以触发延时的条件是前面得有多少帧是moving,否则立即转为静置
- private int m_stationaryDelayTriggerFrames = 150; // 从静置变为moving时,可以触发延时的条件是前面得有多少帧是stationary,否则立即转为moving
- private volatile bool m_manuallyUnfreeze = false; // 手动解冻
- private volatile bool m_enableDebugImageWrite = false;
- private int m_width;
- private int m_height;
- private double m_scale;
- private bool m_bLastImg;
- private bool m_bWork = false;
- private byte[] m_tempData;
- private GCHandle m_hObject;
- private IntPtr m_pTempData;
- private byte[] m_resizedData;
- private GCHandle m_resizedObject;
- private IntPtr m_pResizedData;
- private Queue<double> m_vCorrData = new Queue<double>();
- private Queue<double> m_vDiffData = new Queue<double>();
- private Queue<double> m_vCannyData = new Queue<double>();
- private const string DEBUG_FOLDER_NAME = "AIDebugImages";
- /// <summary>
- /// 构造函数
- /// </summary>
- public VideoStatusInspect()
- {
-
- }
- /// <summary>
- /// 设置延时参数
- /// </summary>
- /// <param name="workingStateDelayFrames">判断是否在扫查中的延时帧数(默认参数是90)
- /// 设成90意味着,如果之前是在扫查中(返回结果为Moving),当医生开始不再扫查后,90帧后返回结果才变成Stationary)</param>
- public void SetWorkingStateDelayFrames(int workingStateDelayFrames)
- {
- m_movingDelayFrames = workingStateDelayFrames;
- }
- public void ManuallyUnfreeze()
- {
- m_manuallyUnfreeze = true;
- }
- public void EnableDebugImagesWrite(bool enable)
- {
- m_enableDebugImageWrite = enable;
- }
- /// <summary>
- /// 销毁
- /// </summary>
- public void Dispose()
- {
- if (m_hObject.IsAllocated)
- {
- m_hObject.Free();
- }
- if (m_tempData != null)
- {
- m_pTempData = IntPtr.Zero;
- Array.Clear(m_tempData, 0, m_tempData.Length);
- m_tempData = null;
- }
- if (m_resizedObject.IsAllocated)
- {
- m_resizedObject.Free();
- }
- if (m_resizedData != null)
- {
- m_pResizedData = IntPtr.Zero;
- Array.Clear(m_resizedData, 0, m_resizedData.Length);
- m_resizedData = null;
- }
- }
- /// <summary>
- /// 传入一帧图进行检测
- /// </summary>
- /// <param name="srcImg">待测图像</param>
- /// <returns>当前时刻是否在扫查中</returns>
- public CurrentVideoState ImgDataCalculateCS(RawImage srcImg)
- {
- if (!CheckInputImageInfo(srcImg.Width, srcImg.Height, srcImg.ColorType))
- {
- return CurrentVideoState.Error;
- }
- if (m_enableDebugImageWrite)
- {
- if (!Directory.Exists(DEBUG_FOLDER_NAME))
- {
- Directory.CreateDirectory(DEBUG_FOLDER_NAME);
- }
- string fileName = "RawImage_"+ DateTime.Now.ToString("yyyyMMdd_HHmm_ssffff");
- string filePath = System.IO.Path.Combine(DEBUG_FOLDER_NAME, fileName + ".txt");
- RawImage.SaveRawImageIntoFile(srcImg, filePath);
- }
- return ImageTransport(srcImg, 1);
- }
- public CurrentVideoState ImgDataCalculateCS(IntptrRawImage srcImg)
- {
- if (!CheckInputImageInfo(srcImg.Width, srcImg.Height, srcImg.ColorType))
- {
- return CurrentVideoState.Error;
- }
- if (m_enableDebugImageWrite)
- {
- if (!Directory.Exists(DEBUG_FOLDER_NAME))
- {
- Directory.CreateDirectory(DEBUG_FOLDER_NAME);
- }
- string fileName = "IntptrRawImage_"+DateTime.Now.ToString("yyyyMMdd_HHmm_ssffff");
- string filePath = System.IO.Path.Combine(DEBUG_FOLDER_NAME, fileName + ".txt");
- int dataLength = srcImg.BytesPerPixel * srcImg.Width * srcImg.Height;
- byte[] datas = new byte[dataLength];
- Marshal.Copy(srcImg.DataPointer, datas, 0, dataLength);
- RawImage image = new RawImage(datas, srcImg.Width, srcImg.Height, srcImg.ColorType);
- RawImage.SaveRawImageIntoFile(image, filePath);
- }
- return ImageTransport(srcImg, 1);
- }
- /// <summary>
- /// 参数设置
- /// </summary>
- private void SetParameterCS()
- {
- m_bLastImg = false;
- m_vCorrData.Clear();
- m_vDiffData.Clear();
- m_vCannyData.Clear();
- double height = (double)(m_LastImg.ImgHeight);
- double width = (double)(m_LastImg.ImgWidth);
- double diagonal = Math.Sqrt(width * height);
- double m_scale = 0.5;
- if (diagonal > 300)
- {
- m_scale = 300 / diagonal;
- }
- else
- {
- m_scale = 1;
- }
- // 如果长宽比不夸张,则直接等比例缩放长和宽
- if (width > 0.5 * height && width < 2 * height)
- {
- m_height = (int)(height * m_scale / 4) * 4;
- m_width = (int)(width * m_scale / 4) * 4;
- }
- else
- {
- // 缩放后短边不要小于200
- if (width >= height)
- {
- m_height = Math.Max((int)(height * m_scale / 4) * 4, 200);
- m_width = (int)(m_height * 1.5);
- }
- else
- {
- m_width = Math.Max((int)(width * m_scale / 4) * 4, 200);
- m_height = (int)(m_width * 1.5);
- }
- }
- if (m_hObject.IsAllocated)
- {
- m_hObject.Free();
- }
- if (m_tempData != null)
- {
- m_pTempData = IntPtr.Zero;
- Array.Clear(m_tempData, 0, m_tempData.Length);
- m_tempData = null;
- }
- m_tempData = new byte[m_width * m_height];
- m_hObject = GCHandle.Alloc(m_tempData, GCHandleType.Pinned);
- m_pTempData = m_hObject.AddrOfPinnedObject();
- if (m_resizedObject.IsAllocated)
- {
- m_resizedObject.Free();
- }
- if (m_resizedData != null)
- {
- m_pResizedData = IntPtr.Zero;
- Array.Clear(m_resizedData, 0, m_resizedData.Length);
- m_resizedData = null;
- }
- m_resizedData = new byte[m_width * m_height];
- m_resizedObject = GCHandle.Alloc(m_resizedData, GCHandleType.Pinned);
- m_pResizedData = m_resizedObject.AddrOfPinnedObject();
- m_state.LastState = false;
- m_state.MovingExtendedState = false;
- m_state.MovingExtendedNum = 0;
- m_state.StationaryExtendedState = false;
- m_state.StationaryExtendedNum = 0;
- m_state.TrueMovingNum = 0;
- m_state.TrueStationaryNum = 0;
- }
- private bool CheckInputImageInfo(int imgWidth, int imgHeight, EnumColorType colorType)
- {
- // 为了避免求resize尺寸时除以0,如果图像尺寸为0,直接先退出
- if (imgWidth <= 0 || imgHeight <= 0)
- {
- return false;
- }
- if (!m_bWork) //认为是第一张数据
- {
- m_LastImg.ImgWidth = imgWidth;
- m_LastImg.ImgHeight = imgHeight;
- m_LastImg.ImgColorType = colorType;
- SetParameterCS();
- m_bWork = true;
- }
- else
- {
- //如果当前参数和上一帧的参数不同,认为当前图像为新视频的第一帧,重新设置参数
- if (m_LastImg.ImgWidth != imgWidth || m_LastImg.ImgHeight != imgHeight || m_LastImg.ImgColorType != colorType)
- {
- m_LastImg.ImgWidth = imgWidth;
- m_LastImg.ImgHeight = imgHeight;
- m_LastImg.ImgColorType = colorType;
- SetParameterCS();
- }
- }
- if (m_LastImg.ImgColorType != EnumColorType.Gray8 && m_LastImg.ImgColorType != EnumColorType.Bgr &&
- m_LastImg.ImgColorType != EnumColorType.Bgra && m_LastImg.ImgColorType != EnumColorType.Rgb &&
- m_LastImg.ImgColorType != EnumColorType.Rgba)
- {
- return false;
- }
- return true;
- }
- private CurrentVideoState ImageTransport(RawImage srcImg, int imgCount)
- {
- CurrentVideoState result = CurrentVideoState.Notjudged;
- if (srcImg.Width <= 0 || srcImg.Height <= 0)
- {
- return CurrentVideoState.Error;
- }
- if (srcImg.ColorType != EnumColorType.Gray8 && srcImg.ColorType != EnumColorType.Bgr &&
- srcImg.ColorType != EnumColorType.Bgra && srcImg.ColorType != EnumColorType.Rgb &&
- srcImg.ColorType != EnumColorType.Rgba)
- {
- return CurrentVideoState.Error;
- }
- if (srcImg.DataBuffer == null)
- {
- return CurrentVideoState.Error;
- }
- GCHandle hObjectSrc = GCHandle.Alloc(srcImg.DataBuffer, GCHandleType.Pinned);
- IntPtr pSrcData = hObjectSrc.AddrOfPinnedObject();
- ConvertImage(pSrcData, srcImg.Width, srcImg.Height, srcImg.ColorType, m_width, m_height ,m_pResizedData);
- if (!m_bLastImg)
- {
- m_resizedData.CopyTo(m_tempData, 0);
- m_bLastImg = true;
- }
- else
- {
- double cannyRatio = 0;
- ProcessOneImage(m_pResizedData, m_width, m_height, EnumColorType.Gray8, ref cannyRatio);
- m_vCannyData.Enqueue(cannyRatio);
- double corr = 0, diff = 0;
- double ratio = CompareTwoImage(m_pTempData, m_pResizedData, m_width, m_height, m_width, ref corr, ref diff);
- m_vDiffData.Enqueue(diff);
- m_vCorrData.Enqueue(corr);
- // 队列数值大于阈值则删除0号元素
- if (m_vCorrData.Count > m_queueSize)
- {
- m_vCorrData.Dequeue();
- m_vDiffData.Dequeue();
- m_vCannyData.Dequeue();
- }
- m_resizedData.CopyTo(m_tempData, 0);
- }
- if (hObjectSrc.IsAllocated)
- {
- hObjectSrc.Free();
- }
- result = JudgeVideoCurrentStatusCS();
- return result;
- }
- private CurrentVideoState ImageTransport(IntptrRawImage srcImg, int imgCount)
- {
- CurrentVideoState result = CurrentVideoState.Notjudged;
- if (srcImg.Width <= 0 || srcImg.Height <= 0)
- {
- return CurrentVideoState.Error;
- }
- if (srcImg.ColorType != EnumColorType.Gray8 && srcImg.ColorType != EnumColorType.Bgr &&
- srcImg.ColorType != EnumColorType.Bgra && srcImg.ColorType != EnumColorType.Rgb &&
- srcImg.ColorType != EnumColorType.Rgba)
- {
- return CurrentVideoState.Error;
- }
- if (srcImg.DataPointer == null || srcImg.DataPointer == IntPtr.Zero)
- {
- return CurrentVideoState.Error;
- }
- ConvertImage(srcImg.DataPointer, srcImg.Width, srcImg.Height, srcImg.ColorType, m_width, m_height, m_pResizedData);
- if (!m_bLastImg)
- {
- m_resizedData.CopyTo(m_tempData, 0);
- m_bLastImg = true;
- }
- else
- {
- double cannyRatio = 0, entropy = 0;
- ProcessOneImage(m_pResizedData, m_width, m_height, EnumColorType.Gray8, ref cannyRatio);
- m_vCannyData.Enqueue(cannyRatio);
- double corr = 0, diff = 0;
- double ratio = CompareTwoImage(m_pTempData, m_pResizedData, m_width, m_height, m_width, ref corr, ref diff);
- m_vDiffData.Enqueue(diff);
- m_vCorrData.Enqueue(corr);
- // 队列数值大于阈值则删除0号元素
- if (m_vCorrData.Count > m_queueSize)
- {
- m_vCorrData.Dequeue();
- m_vDiffData.Dequeue();
- m_vCannyData.Dequeue();
- }
- m_resizedData.CopyTo(m_tempData, 0);
- }
- result = JudgeVideoCurrentStatusCS();
- return result;
- }
- private CurrentVideoState JudgeVideoCurrentStatusCS()
- {
- CurrentVideoState eRet = CurrentVideoState.Notjudged;
- int num = m_vDiffData.Count();
- if (num > m_queueSize - 1)
- {
- double[] diffData = m_vDiffData.ToArray();
- double[] corrData = m_vCorrData.ToArray();
- double[] cannyData = m_vCannyData.ToArray();
- eRet = JudgeImage(diffData, corrData, cannyData,num, m_movingDelayFrames, m_stationaryDelayFrames,
- m_movingDelayTriggerFrames, m_stationaryDelayTriggerFrames,m_manuallyUnfreeze, ref m_state);
- m_manuallyUnfreeze = false;
- }
- return eRet;
- }
- }
- }
|