CT图像处理实现杂记

用c#实现: 

1 ct  文件说明:
说明数据文件
说明图像文件(2进制 8位)
一张CT图像有 512x512 个像素点,在dicom文件中每个像素由2字节表示,所以每张图片约512KB大小。图像中每个像素都是整数,专业名称为 Hounsfield scale 或 CT Number,是描述物质的放射密度的量化值(参考Wikipedia)。上表为常见物质的HU值。


2、读取数据

原始数据:

Data.des中是xml格式数据:<whole>
  <Patient>
    <PatientName>zhang san</PatientName>
    <PatientSex>m</PatientSex>
    <PatientAge>60</PatientAge>
  </Patient>
  <Scan>
    <Hospital>ShenYang Hospital</Hospital>
    <WindowWidth>600</WindowWidth>
    <WindowCenter>400</WindowCenter>
    <ScanTime>2010/06/20 12:30:20</ScanTime>
    <ImageWidth>512</ImageWidth>
    <ImageHeight>512</ImageHeight>
    <XPixelSpacing>0.05</XPixelSpacing>
    <YPixelSpacing>0.05</YPixelSpacing>
    <Interval>0.1</Interval>
  </Scan>
  <Image>
    <Image1>D001_001.0.raw</Image1>
    <Image2>D002_001.0.raw</Image2>
    <Image3>D002_002.0.raw</Image3>
    <Image4>D002_003.0.raw</Image4>
    <Image5>D002_004.0.raw</Image5>
    <Image6>D002_005.0.raw</Image6>
    <Image7>D002_006.0.raw</Image7>
  </Image>
</whole>

患者信息等数据是xml格式通过XmlDocument读取

用记事本打开 des 文件

通过标签描述数据本身
患者姓名  性别  年龄 扫描(scan)等信息

1 我们要把这个文件内容读取到我们程序中

首先我们构建一个对象imageInfo 来描述这些信息 


1、目标 把xml 信息读取到对象中来
2、借用一个xmldocument 对象进行处理

3 xmldocument  完整描述一个xml文件!

xml 文件又着严格的层级结构!

建议大家利用第三方AI 工具生成这些代码,再阅读!

读取图像数据 raw,要把它转为bitmap
ps:https://learn.microsoft.com/zh-CN/dotnet/api/system.drawing.bitmap?view=dotnet-plat-ext-8.0
打开文件:

准备:

        private string fileName= "d:/temp/D001_001.0.raw";        //文件名

        private short[] imageData;       //原始数据
        Bitmap bmpImage;                //显示位图
        private int windowWidth = 300; //窗宽
        private int windowCenter = 100; //窗位
        private int imgWidth = 512;     //图像宽度
        private int imgHeight = 512;    //图像高度

1) File.Open

2)BinaryReader

读取的文件放到一个临时数组当中
3)byte[] tempData = new byte[imgWidth * imgHeight * 2];

4)把tempData  数据读取到imageData 数组当中,这时候要位移运算       imageData[j] = (short)((short)tempData[j * 2 + 1] << 8 | tempData[j*2]);

5)灰度转换

windowCenter、windowCenter和医学有关,自己去查。
        public void Rendering()
        {
            //使用窗宽窗位,创建灰度查找表。图像存储的数据都是正值,而CT值的最小值是1024,查表时下标必须为正,

            //所以此处调整了窗宽窗位
            int offset = 1024;
            Byte[] lookUpTable = new Byte[4096];    //数组元素默认值为0
            int low = windowCenter - windowWidth / 2 + offset;
            int high = windowCenter + windowWidth / 2 + offset;
            for (int i = low; i <= high; i++)
            {
                lookUpTable[i] = (Byte)((i - (windowCenter - windowWidth / 2 + offset)) / (double)windowWidth * 255);
            }
            for (int i = high + 1; i < 4096; i++)
            {
                lookUpTable[i] = 255;
            }

            grayBmp = new byte[imgWidth * imgHeight];
            for (int i = 0; i < imgHeight; i++)
            {
                for (int j = 0; j < imgWidth; j++)
                {
                    short data = (short)(imageData[i * imgWidth + j]);
                    grayBmp[i * imgWidth + j] = lookUpTable[data];
                    int temp = lookUpTable[data];
                    Color pixel = Color.FromArgb(temp, temp, temp);
                    bmpImage.SetPixel(j, i, pixel);     //速度很慢,使用下面的方法把数据一次性传过去
                }
            }

        }

把图像文件信息封装到类当中:

{
    [System.Serializable]
    class MImage
    {
        private string fileName;        //文件名

        private short[] imageData;       //原始数据
        Bitmap bmpImage;                //显示位图
        private int windowWidth = 300; //窗宽
        private int windowCenter = 100; //窗位
        private int imgWidth = 512;     //图像宽度
        private int imgHeight = 512;    //图像高度



        public int ImgWidth
        {
            get { return imgWidth; }
        }
        public int ImgHeight
        {
            get { return imgHeight; }
        }

        public int WindowWidth
        {
            get { return windowWidth; }
            set { windowWidth = value; }
        }
        public int WindowCenter
        {
            get { return windowCenter; }
            set { windowCenter = value; }
        }

        public Bitmap BmpImage
        {
            get { return bmpImage; }
        }

        public MImage(string fileName)
        {
            this.fileName = fileName;
            this.imgWidth = ImageInfo.ImageWidth;
            this.imgHeight = ImageInfo.ImageHeight;
            this.windowWidth = ImageInfo.WindowWidth;
            this.windowCenter = ImageInfo.WindowCenter;
        }

        public Bitmap LoadImage()
        {

        }

 
    }
}

6) 前端渲染  通过graphics 把bitmap呈现在界面。
            Rectangle showRect = new Rectangle();
1 我们通过OnPaint 绘制图像 ,搞个继承panel的自定义组件实现。

通过OnPaint 绘制图像

界面设计布局:

增加子面板的的例子代码:

for (int i = 1; i < 4; i++)
{
    for (int x = 1; x < 4; x++)
    {
        Panel panel1 = new Panel();
        // Initialize the Panel control.
        panel1.Location = new Point(56 + i * 264, 72 + x * 152);
        panel1.Size = new Size(264, 152);
        // Set the Borderstyle for the Panel to three-dimensional.
        panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
        // Initialize the Label and TextBox controls.
        // Add the Panel control to the form.
        this.Controls.Add(panel1);
        // Add the Label and TextBox controls to the Panel.
    }
}

Winform  menu+status+SplitContainer

    
    splicePage   :作为左半边的面板  这个是自定义的 继承了Panel
    
    Child panel:  MImageWnd

    
    创建panel
    1   MImageWnd mw= new  MImageWnd()
    
    2   追加到父容器splicePage   当中   this.Controls.add(mw)

 定位: 左 上位置
    
    设置childPanel  的 height、width:平分splicePage   的长度 宽度

显示 与显示数据分离     
    
    List<MImageWnd >  
    
    我们要干三件工作
    
    1  改变colNum  .rowNum
    
    //清理现场的工作
    2  清空wndList wndList 是我们记录子面板的集合  可以看成是前端的数据模型
    
    3、Controls  remove MImageWnd 

           InitializeComponent();
           Rectangle rect = Screen.GetWorkingArea(this);   //获得屏幕分辨率
           this.WindowState = FormWindowState.Maximized;
           this.mainSplit.SplitterDistance = (int)(this.mainSplit.Width * 4f / 5f);

           this.slicePage = new SlicePage();
           slicePage.Dock = DockStyle.Fill;
           this.mainSplit.Panel1.Controls.Add(slicePage);
           slicePage.CreateControls();

slicePage: 起到父容器及控制器作用:

{
    public partial class SlicePage : Panel
    {
        List<MImageWnd> wndList = new List<MImageWnd>();  //窗口数组
        List<MImage> imgList = new List<MImage>();      //图像数组
        List<AnnoTool> annoList = new List<AnnoTool>();  //标注数组,和图像一一对应

        int rowNum = 3;     //子窗口行数

        int columnNum = 3;  //子窗口列数


        VScrollBar sb = new VScrollBar();
        int scrollBarWidth = 20;

        public List<MImage> ImgList
        {
            get { return imgList; }
            set { imgList = value; }
        }

        public List<AnnoTool> AnnoList
        {
            get { return annoList; }
            set { annoList = value; }
        }

        public SlicePage()
        {
            sb.Minimum = 0;
            sb.Maximum = 0;
            sb.Scroll += new ScrollEventHandler(sb_Scroll);
        }

        public void LoadImage()
        {
            if (imgList == null)
            {
                return;
            }

            int num = imgList.Count < wndList.Count ? imgList.Count : wndList.Count;
            for (int i = 0; i < num; i++)
            {
                wndList[i].SetImage(imgList[i], annoList[i]);
                wndList[i].Invalidate();
                wndList[i].Update();
               // ((MainForm)(this.Parent.Parent.Parent)).ProcessProgressBar();
            }

            sb.Minimum = 0;
            if (imgList.Count % columnNum != 0)
            {
                sb.Maximum = imgList.Count / columnNum;
            }
            else
                sb.Maximum = imgList.Count / columnNum - 1;
            sb.SmallChange = 1;
            sb.LargeChange = rowNum;
            sb.Value = 0;
        }

        public void Rotate()
        {
            foreach (MImageWnd wnd in wndList)
            {
                wnd.Rotate();
            }
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // SlicePage
            // 
            this.Resize += new System.EventHandler(this.SlicePage_Resize);
            this.ResumeLayout(false);
        }

        void sb_Scroll(object sender, ScrollEventArgs e)
        {
            if (imgList == null)
            {
                return;
            }
            int start = e.NewValue * columnNum; //点击滚动条后,从此幅图像开始显示

            int num = (imgList.Count - start) < wndList.Count ? (imgList.Count - start) : wndList.Count;
            for (int i = 0; i < num; i++)
            {
                wndList[i].SetImage(imgList[i + start], annoList[i + start]);
                wndList[i].Invalidate();
                wndList[i].Update();
            }
            for (int i = num; i < wndList.Count; i++)  //多余的窗口,清除它的图像
            {
                wndList[i].ClearImage();
            }
        }

        public void Relayout(int row, int col)
        {
            rowNum = row;
            columnNum = col;
            foreach (MImageWnd wnd in wndList)
            {
                this.Controls.Remove(wnd);
            }
            this.wndList.Clear();
            CreateControls();
            ArrangeControls();
            LoadImage();    //改变了窗口个数以后,重新加载图像
        }

        public void CreateControls()
        {
            for (int i = 0; i < rowNum * columnNum; i++)
            {
                MImageWnd wnd = new MImageWnd();
                wnd.BorderStyle = BorderStyle.FixedSingle;
                this.Controls.Add(wnd);
                wndList.Add(wnd);
            }

            this.Controls.Add(sb);
        }

        private void ArrangeControls()
        {
            if (wndList.Count == 0)
                return;

            int width = (this.Width - scrollBarWidth) / columnNum;
            int height = this.Height / rowNum;
            for (int i = 0; i < rowNum * columnNum; i++)
            {
                wndList[i].Location = new Point(i % columnNum * width, i / columnNum * height);
                wndList[i].ClientSize = new Size(width, height);
            }

            sb.Location = new Point(this.Width - scrollBarWidth, 0);
            sb.Size = new Size(scrollBarWidth, this.Height);
        }

        //此两种写法的详细区别。

        protected override void OnResize(EventArgs eventargs)
        {
            ArrangeControls();
            base.OnResize(eventargs);
        }

        private void SlicePage_Resize(object sender, EventArgs e)
        {
        }

        //public const int USER = 0x0400;
        //public const int WM_TEST = USER + 101;

        //protected override void DefWndProc(ref System.Windows.Forms.Message m)
        //{
        //    switch (m.Msg)
        //    {
        //        case WM_TEST: //处理消息 
        //            MessageBox.Show("haha");
        //            break;
        //        default:
        //            base.DefWndProc(ref m);//调用基类函数处理非自定义消息。 
        //            break;
        //    }
        //} 
    }
}

其中,重要的一点是把数据源设置到子面板当中

                wndList[i].SetImage(imgList[i]);
                wndList[i].Invalidate();
                wndList[i].Update();

 为scrollBar留空间   int scrollBarWidth = 20;

查官网 scrollBar 用法

1 、创建 :VScrollBar sb = new VScrollBar();
 2 、设置 scrollBarWidth  height
3 、add 到父容器

scrollBar5个属性:


value=0  : 滚动的刻度
Maximum=   this.imglist.count%columnNum*rowNum!=0

               this.imglist.count/columnNum*rowNum
               
               this.imglist.count/columnNum*rowNum-1

Minimum=0
SmallChange=1    
LargeChange=rowNum
 

    设置滚动事件

    3*3   
    改参数  2*2  、4*4
    清除 数据模型、实际展示
    
        
    ps:Delegate Class
    类比c函数指针:
    https://learn.microsoft.com/en-us/dotnet/csharp/delegates-overview
    
    
      通过委托来实现事件处理的过程,通常需要以下4个步骤:
    • 定义委托类型,并在发布者类中定义一个该类型的公有成员。
    • 在订阅者类中定义委托处理方法。
    • 订阅者对象将其事件处理方法链接到发布者对象的委托成员(一个委托类型的引用)上。
    • 发布者对象在特定的情况下“激发”委托操作,从而自动调用订阅者对象的委托处理方法。
        
1 打开文件

根据dilalog 中的选择 动态读取xml 文件
xml文件当中的信息 转换为ImageInfo对象、设置  MIMage

我们已经能读取数据,也能形成九宫格,现在要组装到项目中:

form   :读取文件  ——》

    xml----->imageInfo

     数据文件---》   MIMage

        ImageInfo info = new ImageInfo();
        XmlDocument myxml = new XmlDocument();

     ps:     OpenFileDialog
        来自 <https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.openfiledialog?view=windowsdesktop-7.0> 

  更改openfileDialog过滤条件
     dlg.Filter = "图像描述文件 (*.des)|*.des|生数据 (*.raw)|*.raw";
 
调用    

        if (dlg.ShowDialog() == DialogResult.OK)
            {
                slicePage.ImgList.Clear();

                if (dlg.FilterIndex == 1)
                {
                    ParseDesFile(dlg.FileName);
                    //slicePage.LoadImage();  //重绘界面
            }
             }

       

        private void ParseDesFile(string fileName)
        {
            ImageInfo info = new ImageInfo();
            XmlDocument myxml = new XmlDocument();
            myxml.Load(fileName);
            XmlNode root = myxml.DocumentElement;
            XmlNode node = root["Patient"];
            ImageInfo.PatientName = node["PatientName"].InnerText;
            ImageInfo.PatientSex = Convert.ToChar(node["PatientSex"].InnerText);
            ImageInfo.PatientAge = Convert.ToInt32(node["PatientAge"].InnerText);
            node = root["Scan"];
            ImageInfo.HospitalName = node["Hospital"].InnerText;
            ImageInfo.WindowWidth = Convert.ToInt32(node["WindowWidth"].InnerText);
            ImageInfo.WindowCenter = Convert.ToInt32(node["WindowCenter"].InnerText);
            ImageInfo.ScanTime = node["ScanTime"].InnerText;
            ImageInfo.ImageWidth = Convert.ToInt32(node["ImageWidth"].InnerText);
            ImageInfo.ImageHeight = Convert.ToInt32(node["ImageHeight"].InnerText);
            ImageInfo.XPixelSpacing = Convert.ToDouble(node["XPixelSpacing"].InnerText);
            ImageInfo.YPixelSpacing = Convert.ToDouble(node["YPixelSpacing"].InnerText);
            ImageInfo.Interval = Convert.ToDouble(node["Interval"].InnerText);

            node = root["Image"];
            int pos = fileName.LastIndexOf('\\');
            string path = fileName.Substring(0, pos + 1);
            foreach (XmlNode var in node.ChildNodes)
            {
                MImage img = new MImage(path + var.InnerText);
                slicePage.ImgList.Add(img);
            }
        }

    Draw object:
    1. Rectangle
    2. Line
    3. Ellipse
    4. Text

1    创建MImage、 imageInfo 2个文件,  修改namespace  MImage中增加loadImage方法

2   slicePage 起到连接数据与显示模型的桥梁的作用,我们在它当中增加字段与属性,让它认识MImage等
        private List<MImage> imgList = new List<MImage>();      //图像数组
        internal List<MImage> ImgList { get => imgList; set => imgList = value; }
 
控制层:
        /**
         * 把数据模型的数据塞给显示模型  这里不负责渲染  但调用invalate() update() 方法 引起渲染
         * 
         */

        public void LoadImage() {

            for (int i = 0; i < 7; i++)
            {
                wndList[i].SetImage(imgList[i]);
                wndList[i].Invalidate();
                wndList[i].Update();
            }
        }


Mimage: 准备数据,把原始raw数据转换为bitmap数据:

    public Bitmap LoadImage()
    {
        imageData = new short[imgWidth * imgHeight];
        bmpImage = new System.Drawing.Bitmap(imgWidth, imgHeight);

        byte[] tempData = new byte[imgWidth * imgHeight * 2];
        BinaryReader sr = new BinaryReader(File.Open(fileName, FileMode.Open));
        //没有办法直接把数据读到short数组里面,所以借助byte数组转化一下。

        sr.Read(tempData, 0, imgWidth * imgHeight * 2);
        sr.Close();

        for (int i = 0; i < imgWidth * imgHeight; i++)
        {
            imageData[i] = (short)((short)tempData[2 * i + 1] << 8 | tempData[2 * i]);
        }

        Rendering();
        return bmpImage;
    }

            public void Rendering()
            {
                //使用窗宽窗位,创建灰度查找表。图像存储的数据都是正值,而CT值的最小值是1024,查表时下标必须为正,

                //所以此处调整了窗宽窗位
                int offset = 1024;
                Byte[] lookUpTable = new Byte[4096];    //数组元素默认值为0
                int low = windowCenter - windowWidth / 2 + offset;
                int high = windowCenter + windowWidth / 2 + offset;
                for (int i = low; i <= high; i++)
                {
                    lookUpTable[i] = (Byte)((i - (windowCenter - windowWidth / 2 + offset)) / (double)windowWidth * 255);
                }
                for (int i = high + 1; i < 4096; i++)
                {
                    lookUpTable[i] = 255;
                }

                //grayBmp = new byte[imgWidth * imgHeight];
                for (int i = 0; i < imgHeight; i++)
                {
                    for (int j = 0; j < imgWidth; j++)
                    {
                        short data = (short)(imageData[i * imgWidth + j]);
                        //grayBmp[i * imgWidth + j] = lookUpTable[data];
                        int temp = lookUpTable[data];
                        Color pixel = Color.FromArgb(temp, temp, temp);
                        bmpImage.SetPixel(j, i, pixel);     //速度很慢,使用下面的方法把数据一次性传过去
                    }
                }

            }


//绘制数据     

      if (null != mImage)
            {
                double tempFactor;
                if (this.Width / (double)this.Height > mImage.ImgWidth / (double)mImage.ImgHeight)  //如果窗口较宽
                {
                    tempFactor = this.Height / (double)mImage.ImgHeight * factor;
                }
                else
                {
                    tempFactor = this.Width / (double)mImage.ImgWidth * factor;
                }

                showRect.X = (int)((this.Width - mImage.ImgWidth * tempFactor) / 2) + offset.X;
                showRect.Y = (int)((this.Height - mImage.ImgHeight * tempFactor) / 2) + offset.Y;
                showRect.Width = (int)(mImage.ImgWidth * tempFactor);
                showRect.Height = (int)(mImage.ImgHeight * tempFactor);

                e.Graphics.DrawImage(mImage.BmpImage, showRect);

            }


    滚动事件:
    
        动态计算偏移量
      重新设置Imgwnd 的图像数据源
    
    
        加载的时候,loadimg
    
    

                sb.Minimum = 0;
                if (imgList.Count % columnNum != 0)
                {
                    sb.Maximum = imgList.Count / columnNum;
                }
                else
                    sb.Maximum = imgList.Count / columnNum - 1;
                sb.SmallChange = 1;
                sb.LargeChange = rowNum;
                sb.Value = 0;


    
鼠标状态
    

        enum MOUSESTATE
        {
            NONE,
            WL,
            ZOOM,
            MOVE,
            LINE,
            RECT,
            ELLIPSE,
            TEXT
        }

  
    
    
    图像旋转:
         这个基于矩阵变化
     Matrix rotateMatrix = new Matrix();
    
    绘制的时候设置gr转换
    
        
    Wnd:

            public void Rotate()
            {
                Point center = new Point();
                center.X = (showRect.Left + showRect.Right) / 2;
                center.Y = (showRect.Top + showRect.Bottom) / 2;
                rotateMatrix.RotateAt(90, center);
                Invalidate();
                Update();
            }

   
    
    slicePage 循环调用它
    委托:
    

    using System;
    using System.IO;
    
    namespace DelegateAppl
    {
       class PrintString
       {
          static FileStream fs;
          static StreamWriter sw;
          // 委托声明
          public delegate void printString(string s);
    
          // 该方法打印到控制台
          public static void WriteToScreen(string str)
          {
             Console.WriteLine("The String is: {0}", str);
          }
          // 该方法打印到文件
          public static void WriteToFile(string s)
          {
             fs = new FileStream("c:\\message.txt", FileMode.Append, FileAccess.Write);
             sw = new StreamWriter(fs);
             sw.WriteLine(s);
             sw.Flush();
             sw.Close();
             fs.Close();
          }
          // 该方法把委托作为参数,并使用它调用方法
          public static void sendString(printString ps)
          {
             ps("Hello World");
          }
          static void Main(string[] args)
          {
             printString ps1 = new printString(WriteToScreen);
             printString ps2 = new printString(WriteToFile);
             sendString(ps1);
             sendString(ps2);
             Console.ReadKey();
          }
       }
    }


        绘制线段:

1、MImageWnd中 规定位置字段,记录点击位置       

        private int start_x = -1;
        private int start_y = -1;

        private int end_x = -1;
        private int end_y = -1;
		
		
		
		2、构建  MLine 类
		    internal class MLine
    {
        private int start_x = -1;
        private int start_y = -1;

        private int end_x = -1;
        private int end_y = -1;

        public int Start_x { get=> start_x; set=> start_x=value; }
        public int Start_y { get => start_y; set => start_y = value; }

        public int End_x { get => end_x; set => end_x = value; }
        public int End_Y { get => end_y; set => end_y = value; }
    }
	
	
	3、MImageWnd中 添加集合 List<MLine> lines
	
	
	4、   划线方法 public void DrawLineInt(int x0, int y0, int x1, int y1, Graphics g)
    {
     ......
    }

    
    事件定义、订阅、发布处理 的例子代码:
    

using System;
    namespace SimpleEvent
    {
      using System;
      /***********发布器类***********/
      public class EventTest
      {
        private int value;
    
        public delegate void NumManipulationHandler();
    
    
        public event NumManipulationHandler ChangeNum;
        protected virtual void OnNumChanged()
        {
          if ( ChangeNum != null )
          {
            ChangeNum(); /* 事件被触发 */
          }else {
            Console.WriteLine( "event not fire" );
            Console.ReadKey(); /* 回车继续 */
          }
        }
    
    
        public EventTest()
        {
          int n = 5;
          SetValue( n );
        }
    
    
        public void SetValue( int n )
        {
          if ( value != n )
          {
            value = n;
            OnNumChanged();
          }
        }
      }
    
    
      /***********订阅器类***********/
    
      public class subscribEvent
      {
        public void printf()
        {
          Console.WriteLine( "event fire" );
          Console.ReadKey(); /* 回车继续 */
        }
      }
    
      /***********触发***********/
      public class MainClass
      {
        public static void Main()
        {
          EventTest e = new EventTest(); /* 实例化对象,第一次没有触发事件 */
          subscribEvent v = new subscribEvent(); /* 实例化对象 */
          e.ChangeNum += new EventTest.NumManipulationHandler( v.printf ); /* 注册 */
          e.SetValue( 7 );
          e.SetValue( 11 );
        }
      }
    }
    
    e.KeyCode == Keys.Enter


    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/281026.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

近 300 个假冒应用程序泛滥成灾,淹没伊朗银行业

内容概述&#xff1a; 近期&#xff0c;针对伊朗银行业的大规模活动规模不断扩大&#xff0c;近 300 个恶意 Android 应用程序针对用户的账户凭据、信用卡和加密钱包发起攻击。四个月前&#xff0c;Sophos 的研究人员详细介绍了一场漫长的活动&#xff0c;涉及 40 个恶意银行应…

探索全新的设计境界——Autodesk AutoCAD 2020 for Mac/win中文版

在当今数字化时代&#xff0c;设计师们需要一个强大而灵活的工具来实现他们的创意。作为全球领先的设计软件提供商&#xff0c;Autodesk推出了全新的AutoCAD 2020&#xff0c;为设计师们打开了探索全新设计境界的大门。 AutoCAD 2020以其卓越的功能和直观的界面而闻名&#xf…

基于uibot知网文论采集机器人设计与实现

摘要 人工智能技术的不断更新迭代为财务数据自动化处理带来了新的机遇和挑战&#xff0c;如何通过人工智能等新兴技术来优化现有的财务流程&#xff0c; 创造更多的企业价值&#xff0c;成为财务信息自动化处理是目前的重点研究方向。机器人流 程自动化作为一种新型的自动化技…

C#使用switch多路选择语句判断何为季节

目录 一、 switch语句 二、示例 三、生成 一、 switch语句 switch语句是多路选择语句&#xff0c;它通过一个表达式的值来使程序从多个分支中选取一个用于执行的分支。 switch表达式的值只可以是整型、字符串、枚举和布尔类型。 switch语句中多个case可以使用一个break。 在…

ubuntu下编译obs-studio遇到的问题记录

参考的是这篇文档&#xff1a;Build Instructions For Linux obsproject/obs-studio Wiki GitHub 在安装OBS dependencies时&#xff0c; sudo apt install libavcodec-dev libavdevice-dev libavfilter-dev libavformat-dev libavutil-dev libswresample-dev libswscale-d…

Vue Tinymce富文本组件添加自定义字体项

实现效果如下&#xff1a; Tinymce 组件进行字体设置 设置完后&#xff0c;就可以使用自定义的字体了。

CLion中使用C/C++ Single File Execution插件编译和运行单个文件

在开发C/C程序时&#xff0c;尽管项目通常以组织良好的结构进行管理&#xff0c;但有时我们可能只需要快速测试或运行单个C或C源文件。对于这种情况&#xff0c;JetBrains CLion IDE提供了一个便捷的解决方案——通过安装名为“C/C Single File Execution”的插件来实现对单个源…

GcExcel:DsExcel 7.0 for Java Crack

GcExcel:DsExcel 7.0-高速 Java Excel 电子表格 API 库 Document Solutions for Excel&#xff08;DsExcel&#xff0c;以前称为 GcExcel&#xff09;Java 版允许您在 Java 应用程序中以编程方式创建、编辑、导入和导出 Excel 电子表格。几乎可以部署在任何地方。 创建、加载、…

【leetcode100-025】【链表/快慢指针】环形链表

【题干】 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&a…

三子棋(c语言)

前言&#xff1a; 三子棋是一种民间传统游戏&#xff0c;又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏规则是双方对战&#xff0c;双方依次在9宫格棋盘上摆放棋子&#xff0c;率先将自己的三个棋子走成一条线就视为胜利。但因棋盘太小&#xff0c;三子棋在很多时候会出现和…

Linux xxd命令分析视频文件Box教程(box分析box、视频box、分析atom分析)(xdd指令)

文章目录 Linux xxd命令分析视频文件Box教程一、理解MP4格式二、xxd命令简介三、使用xxd命令分析MP4文件四、解析MP4文件的疑难点1. Box的嵌套结构2. 长度和类型字段的字节序3. 非文本类型的数据 五、python代码解析box嵌套结构的示例 Linux xxd命令分析视频文件Box教程 本文主…

AlignBench:量身打造的中文大语言模型对齐评测

对齐&#xff08;Alignment&#xff09;&#xff0c;是指大语言模型&#xff08;LLM&#xff09;与人类意图的一致性。换言之&#xff0c;就是让LLM生成的结果更加符合人类的预期&#xff0c;包括遵循人类的指令&#xff0c;理解人类的意图&#xff0c;进而能产生有帮助的回答等…

2023博客年终总结、你好2024

2023博客年终总结、你好2024 1、2023博客年终总结2、你好2024 1、2023博客年终总结 2023写了100篇博客&#xff0c;祝愿我们的人生都能圆满达到100分。 2023行将结束&#xff0c;有幸接触了一本书 《你怎样过一天&#xff0c;就怎样过一生》 作者 七纤 2、你好2024 你好2024…

如何修改Anaconda的Jupyter notebook的默认启动路径

1.打开Anaconda控制台 2.输入下面的命令 jupyter notebook --generate-config 这个命令的作用是生成 Jupyter notebook 的配置文件。如果你是第一次运行&#xff0c;会直接生成这个文件。如果曾经运行过这个命令&#xff0c;就会像下图一样问你时候要覆盖原来的文件。这个时候…

状态模式-概述

在软件系统中&#xff0c;有些对象也像水一样具有多种状态&#xff0c;这些状态在某些情况下能够相互转换&#xff0c; 而且对象在不同的状态下也将具有不同的行为。相同的方法在不同的状态中可能会有不同的实现。 为了实现不同状态下对象的各种行为以及对象状态之间的相互转换…

PHP序列化总结3--反序列化的简单利用及案例分析

反序列化中生成对象里面的值&#xff0c;是由反序列化里面的值决定&#xff0c;与原类中预定义的值的值无关&#xff0c;穷反序列化的对象可以使用类中的变量和方法 案例分析 反序列化中的值可以覆盖原类中的值 我们创建一个对象&#xff0c;对象创建的时候触发了construct方…

Java多线程<三>常见的多线程设计模式

多线程的设计模式 两阶段线程终止 park方法 interrupted() 会让他失效。 使用volatile关键字进行改写 单例模式 双锁检测 保护性暂停 实现1&#xff1a; package threadBase.model;/*** author: Zekun Fu* date: 2022/5/29 19:01* Description:* 保护性暂停&#xff0c;* …

HarmonyOS4.0系统性深入开发09卡片使用动效能力

卡片使用动效能力 ArkTS卡片开放了使用动画效果的能力&#xff0c;支持显式动画、属性动画、组件内转场能力。需要注意的是&#xff0c;ArkTS卡片使用动画效果时具有以下限制&#xff1a; 名称参数说明限制描述duration动画播放时长限制最长的动效播放时长为1秒&#xff0c;当…

5天一更新的卫星影像数据来自哪里?

这里我们就来分享一下&#xff0c;5天一更新的卫星影像源来自哪里。 哥白尼计划 在开始讲卫星影像数据源时&#xff0c;我们先来了解一下什么是哥白尼计划。 哥白尼计划&#xff08;Copernicus Programme&#xff09;&#xff0c;又称全球环境与安全监测计划&#xff08;Glo…

用通俗易懂的方式讲解大模型:LangChain Agent 原理解析

LangChain 是一个基于 LLM&#xff08;大型语言模型&#xff09;的编程框架&#xff0c;旨在帮助开发人员使用 LLM 构建端到端的应用程序。它提供了一套工具、组件和接口&#xff0c;可以简化创建由 LLM 和聊天模型提供支持的应用程序的过程。 LangChain 由几大组件构成&#…