C#数字图像处理(三)

news2025/6/5 13:22:53

文章目录

  • 前言
  • 1.图像平移
    • 1.1 图像平移定义
    • 1.2 图像平移编程实例
  • 2.图像镜像
    • 2.1 图像镜像定义
    • 2.2 图像镜像编程实例
  • 3.图像缩放
    • 3.1 图像缩放定义
    • 3.2 灰度插值法
    • 3.3 图像缩放编程实例
  • 4.图像旋转
    • 4.1 图像旋转定义
    • 4.2 图像旋转编程实例

前言

  在某种意义上来说,图像的几何运算是与点运算相对立的。它改变了像素之间的空间位置和空间关系,但它没有改变灰度等级值。几何运算需要两个独立的算法:空间变换灰度值插值
  在本章所介绍的几何运算中,应用空间变换算法对图像进行平移、镜像处理,应用空间变换和灰度值插值算法对图像进行缩放和旋转处理。
  需要说明的是,在这里,以图像的几何中心作为坐标原点,x轴由左向右递增,y轴由上至下递增。
  因此,在进行图像旋转时,是以图像的几何中心为基准进行旋转的:在进行图像缩放时,也是以图像的几何中心为基准,其上下左右均等地向内收缩或向外扩大的。这种坐标转换会使图像变换更自然。另外,在进行几何运算的时候,保持原图像的尺寸大小不变,如果变换后的图像超出该尺寸,超出部分会被截断,而不足部分会以白色像素填充。

1.图像平移

1.1 图像平移定义

在这里插入图片描述

1.2 图像平移编程实例

  该实例通过设置横向和纵向的平移量,实现了图像的平移。
在这里插入图片描述
  分别为该窗体内的2个Button控件添加Click事件,为了和主窗体之间传递数据,再添加2个get属性访问器,代码如下:

  public partial class translation : Form
 {
     public translation()
     {
         InitializeComponent();
     }

     private void start_Click(object sender, EventArgs e)
     {
         this.DialogResult = DialogResult.OK;
     }

     private void close_Click(object sender, EventArgs e)
     {
         this.Close();
     }

     public string GetXOffset
     {
         get
         {
             //横向平移量
             return xOffset.Text;
         }
     }

     public string GetYOffset
     {
         get
         {
             //纵向平移量
             return yOffset.Text;
         }
     }
 }

  回到主窗体,为“图像平移”按钮添加Click事件,代码如下:

 /// <summary>
        /// 图像平移
        /// </summary>
        private void translation_Click(object sender, EventArgs e)
        {
            if (curBitmap!=null)
            {
                translation traForm = new translation();
                if (traForm.ShowDialog()==DialogResult.OK)
                {
                    Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                    BitmapData bmpData = curBitmap.LockBits(rect, ImageLockMode.ReadWrite, curBitmap.PixelFormat);
                    IntPtr ptr = bmpData.Scan0;
                    int bytes = bmpData.Stride * bmpData.Height;
                    byte[] grayValues = new byte[bytes];
                    Marshal.Copy(ptr, grayValues, 0, bytes);

                    //得到两个方向的图像平移量
                    int x = Convert.ToInt32(traForm.GetXOFFset);
                    int y = Convert.ToInt32(traForm.GetYOffset);

                    byte[] tempArray = new byte[bytes];
                    //临时初始化为白色(255)像素
                    for (int i = 0; i < bytes; i++)
                    {
                        tempArray[i] = 255;
                    }
                    
                    for (int j = 0; j < curBitmap.Height; j++)
                    {//保证纵向平移不出界
                        if ((j + y) < curBitmap.Height && (j + y) > 0)
                        {
                            for (int i = 0; i < curBitmap.Width * 3; i += 3)
                            {
                                if ((i + x * 3) < curBitmap.Width * 3 && (i + x * 3) > 0)
                                {//保证横向平移不出界
                                    tempArray[(i + x * 3) + 0 + (j + y) * bmpData.Stride] = grayValues[i + 0 + j * bmpData.Stride];
                                    tempArray[i + x * 3 + 1 + (j + y) * bmpData.Stride] = grayValues[i + 1 + j * bmpData.Stride];
                                    tempArray[i + x * 3 + 2 + (j + y) * bmpData.Stride] = grayValues[i + 2 + j * bmpData.Stride];
                                }
                            }
                        }
                    }


                    //数组复制,返回平移图像
                    grayValues = (byte[])tempArray.Clone();
                    Marshal.Copy(grayValues, 0, ptr, bytes);
                    curBitmap.UnlockBits(bmpData);
                }
                Invalidate();
            }

  要注意像素格式PixelFormat,如24位灰度图像是1440万色,但是我们书上给的算法是对8为进行处理,可以采用分割的思想将24位拆开成3个8位,由这三个8为所保存的数据组合为24位,在处理的时候就将他们分开处理但是要整体观看。

在这里插入图片描述

2.图像镜像

2.1 图像镜像定义

  镜像是一个物体相对于一个镜面的复制品。图像镜像分为水平镜像垂直镜像两种。
  水平镜像就是将图像左半部分和右半部分以图像垂直中轴线为中心镜像进行对换;
   垂直镜像就是将图像上半部分和下半部分以图像水平中轴线为中心镜像进行对换。
在这里插入图片描述

2.2 图像镜像编程实例

该实例实现了图像的水平镜像和垂直镜像。
在这里插入图片描述
  分别为该窗体内的2个Button控件添加Click事件,并再添加1个get属性访问器,代码如下:

    private void startMirror_Click(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.OK;
    }

    private void close_Click(object sender, EventArgs e)
    {
        this.Close();
    }

    public bool GetMirror
    {
        get
        {
            return horMirror.Checked;
        }
    }
}

  回到主窗体,为“图像镜像”按钮添加Click事件,代码如下:

private void mirror_Click(object sender, EventArgs e)
        {
            if (curBitmap!=null)
            {
                mirror mirForm = new mirror();
                if (mirForm.ShowDialog()==DialogResult.OK)
                {
                    Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                    BitmapData bmpData = curBitmap.LockBits(rect, ImageLockMode.ReadWrite, curBitmap.PixelFormat);
                    IntPtr ptr = bmpData.Scan0;
                    int bytes = 0;
                    判断是灰度色图像还是彩色图像,给相应的大小
                    if (curBitmap.PixelFormat==PixelFormat.Format8bppIndexed)
                    {
                        bytes= curBitmap.Width * curBitmap.Height;
                    }
                    else if (curBitmap.PixelFormat == PixelFormat.Format24bppRgb)
                    {
                        bytes = curBitmap.Width * curBitmap.Height * 3;
                    }
                    byte[] pixelValues = new byte[bytes];
                    Marshal.Copy(ptr, pixelValues, 0, bytes);

                    //水平中轴
                    int halfWidth = curBitmap.Width / 2;
                    //垂直中轴
                    int halfHeight = curBitmap.Height / 2;
                    byte temp;
                    byte temp1;
                    byte temp2;
                    byte temp3;
                    if (curBitmap.PixelFormat == PixelFormat.Format8bppIndexed)
                    {
                        if (mirForm.GetMirror)
                        {
                            for (int i = 0; i < curBitmap.Height; i++)
                                for (int j = 0; j < halfWidth; j++)
                                {
                                    temp = pixelValues[i * curBitmap.Width + j];
                                    pixelValues[i * curBitmap.Width + j] = pixelValues[(i + 1) * curBitmap.Width - j - 1];
                                    pixelValues[(i + 1) * curBitmap.Width - j - 1] = temp;
                                }
                        }
                        else
                        {
                            for (int j = 0; j < curBitmap.Width; j++)
                            {
                                for (int i = 0; i < halfHeight; i++)
                                {
                                    temp = pixelValues[i * curBitmap.Width + j];
                                    pixelValues[i * curBitmap.Width + j] = pixelValues[(curBitmap.Height - i - 1) * curBitmap.Width + j];
                                    pixelValues[(curBitmap.Height - i - 1) * curBitmap.Width + j] = temp;
                                }
                            }
                        }
                    }
                    else if (curBitmap.PixelFormat == PixelFormat.Format24bppRgb)
                    {
                        if (mirForm.GetMirror)
                        {
                            //水平镜像处理  
                            for (int i = 0; i < curBitmap.Height; i++)
                            {
                                //每个像素的三个字节在水平镜像时顺序不能变,所以这个方法不能用
                                //for (int j = 0; j < halfWidth; j++)
                                //{
                                //    //以水平中轴线为对称轴,两边像素值交换  
                                //    temp = pixelValues[i * curBitmap.Width * 3 + j * 3];
                                //    pixelValues[i * curBitmap.Width * 3 + j * 3] = pixelValues[(i + 1) * curBitmap.Width * 3 - 1 - j * 3];
                                //    pixelValues[(i + 1) * curBitmap.Width * 3 - 1 - j * 3] = temp;
                                //}
                                for (int j = 0; j < halfWidth; j++)
                                {//每三个字节组成一个像素,顺序不能乱
                                    temp = pixelValues[0 + i * curBitmap.Width * 3 + j * 3];
                                    temp1 = pixelValues[1 + i * curBitmap.Width * 3 + j * 3];
                                    temp2 = pixelValues[2 + i * curBitmap.Width * 3 + j * 3];
                                    pixelValues[0 + i * curBitmap.Width * 3 + j * 3] = pixelValues[0 + (i + 1) * curBitmap.Width * 3 - (j + 1) * 3];
                                    pixelValues[1 + i * curBitmap.Width * 3 + j * 3] = pixelValues[1 + (i + 1) * curBitmap.Width * 3 - (j + 1) * 3];
                                    pixelValues[2 + i * curBitmap.Width * 3 + j * 3] = pixelValues[2 + (i + 1) * curBitmap.Width * 3 - (j + 1) * 3];
                                    pixelValues[0 + (i + 1) * curBitmap.Width * 3 - (j + 1) * 3] = temp;
                                    pixelValues[1 + (i + 1) * curBitmap.Width * 3 - (j + 1) * 3] = temp1;
                                    pixelValues[2 + (i + 1) * curBitmap.Width * 3 - (j + 1) * 3] = temp2;
                                }
                            }
                        }
                        else
                        {
                            //垂直镜像处理  
                            for (int i = 0; i < curBitmap.Width * 3; i++)
                            {
                                for (int j = 0; j < halfHeight; j++)
                                {
                                    //以垂直中轴线为对称轴。两边像素值互换  
                                    temp = pixelValues[j * curBitmap.Width * 3 + i];
                                    pixelValues[j * curBitmap.Width * 3 + i] = pixelValues[(curBitmap.Height - j - 1) * curBitmap.Width * 3 + i];
                                    pixelValues[(curBitmap.Height - j - 1) * curBitmap.Width * 3 + i] = temp;
                                }
                            }
                        }
                    }

                        Marshal.Copy(pixelValues, 0, ptr, bytes);
                    curBitmap.UnlockBits(bmpData);
                }
                Invalidate();
            }
        }
原图

在这里插入图片描述

水平镜像

在这里插入图片描述

垂直镜像

在这里插入图片描述

3.图像缩放

  在图像缩放运算和图像旋转运算中,要用到灰度插值算法,因此这里给出灰度插值的两种算法。

3.1 图像缩放定义

在这里插入图片描述

3.2 灰度插值法

  应用公式(4.5)所产生的图像中的像素有可能在原图像中找不到相应的像素点,因为数字图像中的坐标总是整数。这样就必须进行近似处理。一般是应用灰度插值法。它包括最近邻插值双线性插值
  最近邻插值也称零阶插值,是最简单的插值方法。其做法是令输出像素的灰度值等于离它所映射到的位置最近的输入像素的灰度值。该插值计算虽然十分简单,但它会带来锯齿形的边,图像中也会出现孔洞和重叠。
  双线性插值也称一阶插值,该方法是求到相邻的4个方格上点的距离之比,用这个比率和4个邻点像素的灰度值进行灰度插值,具体方法如下。
在这里插入图片描述
  双线性插值法计算量大,但缩放后图像质量高,不会出现像素值不连续的情况。由于双线性插值具有低通滤波器的性质,使高频分量受损,所以可能会使图像轮廓在一定程度上变得模糊。

3.3 图像缩放编程实例

  该实例应用最近邻插值法和双线性插值法实现图像的缩放。
  在主窗体内添加1个Button控件,其属性修改如表4.5所示。
在这里插入图片描述
   创建1个名为zoom 的 Windows窗体,该窗体用于选择缩放量及用何种灰度插值法。为该窗体添加2个Button控件、1个GroupBox控件、2个RadioButton 控件、2个Label 控件和2个TextBox控件,其属性修改如表4.6所示。
在这里插入图片描述
  分别为该窗体内的2个Button控件添加Click事件,并再添加3个get属性访问器,代码如下:

   private void startZoom_Click(object sender, EventArgs e)
  {
      if (xZoom.Text == "0" || yZoom.Text == "0")
      {
          MessageBox.Show("缩放量不能为0!\n请重新正确填写。", "警告", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
      }
      else
      {
          this.DialogResult = DialogResult.OK;
      }
  }

  private void close_Click(object sender, EventArgs e)
  {
      this.Close();
  }

  public bool GetNearOrBil
  {
      get
      {
          //判断是最近邻插值法还是双线性插值法
          return nearestNeigh.Checked;
      }
  }

  public string GetXZoom
  {
      get
      {
          //得到横向缩放量
          return xZoom.Text;
      }
  }

  public string GetYZoom
  {
      get
      {
          //得到纵向缩放量
          return yZoom.Text;
      }
  }

  回到主窗体,为“图像缩放”按钮控件添加Click事件代码,代码如下:

   private void zoom_Click(object sender, EventArgs e)
   {
       if (curBitmap != null)
       {
           zoom zoomForm = new zoom();
           if (zoomForm.ShowDialog() == DialogResult.OK)
           {
               Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
               System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);
               IntPtr ptr = bmpData.Scan0;
               int bytes = curBitmap.Width * curBitmap.Height;
               byte[] grayValues = new byte[bytes];
               System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
               
               double x = Convert.ToDouble(zoomForm.GetXZoom);
               double y = Convert.ToDouble(zoomForm.GetYZoom);

               int halfWidth = (int)(curBitmap.Width / 2);
               int halfHeight = (int)(curBitmap.Height / 2);

               int xz = 0;
               int yz = 0;
               int tempWidth = 0;
               int tempHeight = 0;

               byte[] tempArray = new byte[bytes];

               if (zoomForm.GetNearOrBil == true)
               {
                   for (int i = 0; i < curBitmap.Height; i++)
                   {
                       for (int j = 0; j < curBitmap.Width; j++)
                       {
                           tempHeight = i - halfHeight;
                           tempWidth = j - halfWidth;
                           if (tempWidth > 0)
                           {
                               xz = (int)(tempWidth / x + 0.5);
                           }
                           else
                           {
                               xz = (int)(tempWidth / x - 0.5);
                           }
                           if (tempHeight > 0)
                           {
                               yz = (int)(tempHeight / y + 0.5);
                           }
                           else
                           {
                               yz = (int)(tempHeight / y - 0.5);
                           }

                           tempWidth = xz + halfWidth;
                           tempHeight = yz + halfHeight;
                           if (tempWidth < 0 || tempWidth >= curBitmap.Width || tempHeight < 0 || tempHeight >= curBitmap.Height)
                           {
                               tempArray[i * curBitmap.Width + j] = 255;
                           }
                           else
                           {
                               tempArray[i * curBitmap.Width + j] = grayValues[tempHeight * curBitmap.Width + tempWidth];
                           }
                       }
                   }
               }
               else
               {
                   double tempX, tempY, p, q;
                   for (int i = 0; i < curBitmap.Height; i++)
                   {
                       for (int j = 0; j < curBitmap.Width; j++)
                       {
                           tempHeight = i - halfHeight;
                           tempWidth = j - halfWidth;
                           tempX = tempWidth / x;
                           tempY = tempHeight / y;
                           if (tempWidth > 0)
                           {
                               xz = (int)tempX;
                           }
                           else
                           {
                               xz = (int)(tempX - 1);
                           }
                           if (tempHeight > 0)
                           {
                               yz = (int)tempY;
                           }
                           else
                           {
                               yz = (int)(tempY - 1);
                           }

                           p = tempX - xz;
                           q = tempY - yz;
                           tempWidth = xz + halfWidth;
                           tempHeight = yz + halfHeight;
                           if (tempWidth < 0 || (tempWidth + 1) >= curBitmap.Width || tempHeight < 0 || (tempHeight + 1) >= curBitmap.Height)
                           {
                               tempArray[i * curBitmap.Width + j] = 255;
                           }
                           else
                           {
                               tempArray[i * curBitmap.Width + j] = (byte)((1.0 - q) * ((1.0 - p) * grayValues[tempHeight * curBitmap.Width + tempWidth] + p * grayValues[tempHeight * curBitmap.Width + tempWidth + 1]) + 
                                   q * ((1.0 - p) * grayValues[(tempHeight + 1) * curBitmap.Width + tempWidth] + p * grayValues[(tempHeight + 1) * curBitmap.Width + 1 + tempWidth]));
                           }
                       }
                   }

               }

               grayValues = (byte[])tempArray.Clone();

               System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
               curBitmap.UnlockBits(bmpData);
           }

           Invalidate();

       }
   }

在这里插入图片描述
在这里插入图片描述

最近邻插值放大5倍

在这里插入图片描述

双线性插值放大5倍

在这里插入图片描述

4.图像旋转

4.1 图像旋转定义

在这里插入图片描述
  同理,旋转后得到的图像像素也有可能在原图像中找不到相应的像素点,因此旋转处理也要用到插值法。由于双线性插值法在图像处理性能上要好过最近邻插值,因此,我们只应用双线性插值这一种方法对图像进行旋转处理。

4.2 图像旋转编程实例

  该实例实现了任意角度的图像旋转。
  1).在主窗体内添加1个Button 控件,其属性修改如表4.7所示。
在这里插入图片描述
  2).创建1个名为rotation的 Windows窗体,该窗体用于选择旋转的角度。为该窗体添加2个Button控件、1个Label控件和1个TextBox控件,其属性修改如表4.8所示。
在这里插入图片描述
在这里插入图片描述
  分别为该窗体内的2个Button控件添加Cick事件,并再添加1个get属性访问器,代码如下:

  private void startRot_Click(object sender, EventArgs e)
  {
      this.DialogResult = DialogResult.OK;
  }

  private void close_Click(object sender, EventArgs e)
  {
      this.Close();
  }

  public string GetDegree
  {
      get
      {
         //得到所要旋转的角度
          return degree.Text;
      }
  }

  回到主窗体,为“图像旋转”按钮控件添加Click事件,代码如下:

  private void rotation_Click(object sender, EventArgs e)
 {
     if (curBitmap != null)
     {
         rotation rotForm = new rotation();
         if (rotForm.ShowDialog() == DialogResult.OK)
         {
             Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
             System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmap.PixelFormat);
             IntPtr ptr = bmpData.Scan0;
             int bytes = curBitmap.Width * curBitmap.Height;
             byte[] grayValues = new byte[bytes];
             System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);

             int degree = Convert.ToInt32(rotForm.GetDegree);
             double radian = degree * Math.PI / 180.0;
             double mySin = Math.Sin(radian);
             double myCos = Math.Cos(radian);
             int halfWidth = (int)(curBitmap.Width / 2);
             int halfHeight = (int)(curBitmap.Height / 2);
             int xr = 0;
             int yr = 0;
             int tempWidth = 0;
             int tempHeight = 0;

             byte[] tempArray = new byte[bytes];
            
             double tempX, tempY, p, q;
             for (int i = 0; i < curBitmap.Height; i++)
             {
                 for (int j = 0; j < curBitmap.Width; j++)
                 {
                     tempHeight = i - halfHeight;
                     tempWidth = j - halfWidth;
                     tempX = tempWidth * myCos - tempHeight * mySin;
                     tempY = tempHeight * myCos + tempWidth * mySin;
                     if (tempWidth > 0)
                     {
                         xr = (int)tempX;
                     }
                     else
                     {
                         xr = (int)(tempX - 1);
                     }
                     if (tempHeight > 0)
                     {
                         yr = (int)tempY;
                     }
                     else
                     {
                         yr = (int)(tempY - 1);
                     }

                     p = tempX - xr;
                     q = tempY - yr;
                     tempWidth = xr + halfWidth;
                     tempHeight = yr + halfHeight;
                     if (tempWidth < 0 || (tempWidth + 1) >= curBitmap.Width || tempHeight < 0 || (tempHeight + 1) >= curBitmap.Height)
                     {
                         tempArray[i * curBitmap.Width + j] = 255;
                     }
                     else
                     {
                         tempArray[i * curBitmap.Width + j] = (byte)((1.0 - q) * ((1.0 - p) * grayValues[tempHeight * curBitmap.Width + tempWidth] + p * grayValues[tempHeight * curBitmap.Width + tempWidth + 1]) +
                             q * ((1.0 - p) * grayValues[(tempHeight + 1) * curBitmap.Width + tempWidth] + p * grayValues[(tempHeight + 1) * curBitmap.Width + 1 + tempWidth]));
                     }

                 }
             }

             grayValues = (byte[])tempArray.Clone();

             System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
             curBitmap.UnlockBits(bmpData);
         }

         Invalidate();
     }
 }

在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL Transactions(事务)、隔离机制

目录 Why Transactions? Example: Bad Interaction Transactions ACID Transactions COMMIT ROLLBACK How the Transaction Log Works How Data Is Stored Example: Interacting Processes Interleaving of Statements Example: Strange Interleaving Fixing the…

【机器学习基础】机器学习入门核心:Jaccard相似度 (Jaccard Index) 和 Pearson相似度 (Pearson Correlation)

机器学习入门核心&#xff1a;Jaccard相似度 &#xff08;Jaccard Index&#xff09; 和 Pearson相似度 &#xff08;Pearson Correlation&#xff09; 一、算法逻辑Jaccard相似度 (Jaccard Index)**Pearson相似度 (Pearson Correlation)** 二、算法原理与数学推导1. Jaccard相…

QT之头像剪裁效果实现

文章目录 源码地址&#xff0c;环境&#xff1a;QT5.15&#xff0c;MinGW32位效果演示导入图片设置剪裁区域创建剪裁小窗口重写剪裁小窗口的鼠标事件mousePressEventmouseMoveEventmouseReleaseEvent 小窗口移动触发父窗口的重绘事件剪裁效果实现 源码地址&#xff0c;环境&…

【GPT入门】第40课 vllm与ollama特性对比,与模型部署

【GPT入门】第40课 vllm与ollama特性对比&#xff0c;与模型部署 1.两种部署1.1 vllm与ollama特性对比2. vllm部署2.1 服务器准备2.1 下载模型2.2 提供模型服务 1.两种部署 1.1 vllm与ollama特性对比 2. vllm部署 2.1 服务器准备 在autodl 等大模型服务器提供商&#xff0c;…

unity开发棋牌游戏

使用unity开发的棋牌游戏&#xff0c;目前包含麻将、斗地主、比鸡、牛牛四种玩法游戏。 相关技术 客户端&#xff1a;unity 热更新&#xff1a;xlua 服务器&#xff1a;c Web服务器&#xff1a;ruoyi 游戏视频 unity开发棋牌游戏 游戏截图

Nat Commun项目文章 ▏小麦CUTTag助力解析转录因子TaTCP6调控小麦氮磷高效利用机制

今年2月份发表在《Nature Communications》&#xff08;IF14.4&#xff09;的“TaTCP6 is required for efficientand balanced utilization of nitrate and phosphorus in wheat”揭示了TaTCP6在小麦氮磷利用中的关键调控作用&#xff0c;为优化肥料利用和提高作物产量提供了理…

C 语言开发中常见的开发环境

目录 1.Dev-C 2.Visual Studio Code 3.虚拟机 Linux 环境 4.嵌入式 MCU 专用开发环境 1.Dev-C 使用集成的 C/C 开发环境&#xff08;适合基础学习&#xff09;,下载链接Dev-C下载 - 官方正版 - 极客应用 2.Visual Studio Code 结合 C/C 扩展 GCC/MinGW 编译器&#xff0c…

vscode命令行debug

vscode命令行debug 一般命令行debug会在远程连服务器的时候用上&#xff0c;命令行debug的本质是在执行时暴露一个监听端口&#xff0c;通过进入这个端口&#xff0c;像本地调试一样进行。 这里提供两种方式&#xff1a; 直接在命令行中添加debugpy&#xff0c;适用于python…

Matlab作图之 subplot

1. subplot(m, n, p) 将当前图形划分为m*n的网格&#xff0c;在 p 指定的位置创建坐标轴 matlab 按照行号对子图的位置进行编号 第一个子图是第一行第一列&#xff0c;第二个子图是第二行第二列......... 如果指定 p 位置存在坐标轴&#xff0c; 此命令会将已存在的坐标轴设…

【机器学习基础】机器学习入门核心算法:层次聚类算法(AGNES算法和 DIANA算法)

机器学习入门核心算法&#xff1a;层次聚类算法&#xff08;AGNES算法和 DIANA算法&#xff09; 一、算法逻辑二、算法原理与数学推导1. 距离度量2. 簇间距离计算&#xff08;连接标准&#xff09;3. 算法伪代码&#xff08;凝聚式&#xff09; 三、模型评估1. 内部评估指标2. …

Google Play的最新安全变更可能会让一些高级用户无法使用App

喜欢Root或刷机的Android用户要注意了&#xff0c;Google最近全面启用了新版Play Integrity API&#xff0c;可能会导致部分用户面临无法使用某些App的窘境。Play Integrity API是Google提供给开发者的工具&#xff0c;用于验证App是否在“未修改”的设备上运行。 许多重要应用…

React---day5

4、React的组件化 组件的分类&#xff1a; 根据组件的定义方式&#xff0c;可以分为&#xff1a;函数组件(Functional Component )和类组件(Class Component)&#xff1b;根据组件内部是否有状态需要维护&#xff0c;可以分成&#xff1a;无状态组件(Stateless Component )和…

Java开发之定时器学习

面试 一、线程池实现定时器 核心代码&#xff1a; public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService Executors.newScheduledThreadPool(5);Runnable runnable () -> System.out.println("当前线程"Thread.current…

HealthBench医疗AI评估基准:技术路径与核心价值深度分析(上)

引言:医疗AI评估的新范式 在人工智能技术迅猛发展的当下,医疗AI系统已逐渐从实验室走向临床应用。然而,医疗领域的特殊性要求这些系统不仅需要在技术指标上表现出色,更需要在实际临床场景中展现出可靠、安全且有效的性能。长期以来,医疗AI评估领域面临着三个核心挑战:评…

Windows+VSCode搭建小智(xiaozhi)开发环境

作为一名DIY达人&#xff0c;肯定不会错过最近很火的“小智AI聊天机器人”&#xff0c;网上教程非常丰富&#xff0c;初级玩家可以直接在乐鑫官方下载ESP-IDF安装包并经过简单的菜单式配置后&#xff0c;即可进行代码编译和烧录&#xff08;详见&#xff1a;Docs&#xff09;。…

VueScan Pro v9.8.45.08 一款图像扫描软件,中文绿色便携版

VueScan是著名的第三方底片扫描仪驱动程序&#xff0c;支持市场可见绝大多数型号的底片扫描仪&#xff0c;可以更为灵活地控制扫描过程&#xff0c;更深入地发掘硬件潜力&#xff0c;获取色彩 完美的高质量扫描结果。VueScan支持200种以上的底片类型&#xff0c;在剪取图像时制…

FreeRTOS通俗理解指南:基础概念 + 架构+ 内核组件+练手实验

RTOS 基础概念 想象一下&#xff0c;你是一个忙碌的厨师&#xff0c;在厨房里同时要完成煎牛排和煮意大利面两项任务。 1.传统单线程模式&#xff08;没有RTOS&#xff09; 如果你只能按顺序一项一项地做&#xff0c;就会是这样的过程&#xff1a; 先煎一会儿牛排然后去看看…

房屋租赁系统 Java+Vue.js+SpringBoot,包括房屋信息、看房申请、租赁合同、房屋报修、收租信息、维修数据、租客管理、公告管理模块

房屋租赁系统 JavaVue.jsSpringBoot&#xff0c;包括房屋信息、看房申请、租赁合同、房屋报修、收租信息、维修数据、租客管理、公告管理模块 百度云盘链接&#xff1a;https://pan.baidu.com/s/16YRGBPsfbd4_HxXhO0jM5Q 密码&#xff1a;smk4 摘 要 房屋是人类生活栖息的重要…

ASP.NET MVC添加视图示例

ASP.NET MVC高效构建Web应用- 商品搜索 - 京东 视图&#xff08;V&#xff09;是一个动态生成HTML页面的模板&#xff0c;它负责通过用户界面展示内容。本节将修改HelloWorldController类&#xff0c;并使用视图模板文件&#xff0c;以干净地封装生成对客户端的HTML响应的过程…

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Form Wave(表单label波动效果)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— FormWave组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ &#x1f3af; 组件目标 构建一个美观、动态的登录表单&#xff0…