【转】c#数字图像处理(二)彩色图像灰度化,灰度图像二值化

转自:https://www.cnblogs.com/dearzhoubi/p/8571652.html

为加快处理速度,在图像处理算法中,往往需要把彩色图像转换为灰度图像,在灰度图像上得到验证的算法,很容易移
植到彩色图像上。
24位彩色图像每个像素用3个字节表示,每个字节对应着R、G、B分量的亮度(红、绿、蓝)。当R、G、B分量值不同时,表现为彩色图像;当R、G、B分量值相同时,表现为灰度图像,该值就是我们所求的一般来说,转换公式有3种。第一种转换公式为:

Gray(i,j)=[R(i,j)+G(i,j)+B(i,j)]÷3            (2.1)

其中,Gray(i,j)为转换后的灰度图像在(i,j)点处的灰度值。该方法虽然简单,但人眼对颜色的感应是不同的,因此有了第二种转换公式:

Gray(i,j)=0299R(i,j)+0.587×G(i,j)+0.114×B(i,j)      (2.2)

观察上式,发现绿色所占的比重最大,所以转换时可以直接使用G值作为转换后的灰度

Gray(i,j)=G(i,j)                    (2.3)

在这里,我们应用最常用的公式(2.2),并且变换后的灰度图像仍然用24位图像表示。

1.提取像素法

这种方法简单易懂,但相当耗时,完全不可取.
该方法使用的是GD+中的 Bitmap Getpixel和 BitmapSetpixel.方法。为了将位图的颜色设置为灰度或其他颜色,就需要使用 Gepiⅸxel来读取当前像素的颜色,再计算灰度值,最后使用 Setpixel来应用新的颜色。双击“提取像素法” Button控件,为该控件添加 Click事件,

代码如下:

复制代码

     /// <summary>/// 提取像素法/// </summary>private void pixel_Click(object sender, EventArgs e){if (curBitmpap != null){Color curColor;int ret;//二维图像数组循环for(int i = 0; i < curBitmpap.Width; i++){for(int j = 0; j < curBitmpap.Height; j++){//获取该像素点的RGB颜色值curColor = curBitmpap.GetPixel(i, j);//利用公式计算灰度值ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);//设置该像素点的灰度值,R=G=B=retcurBitmpap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));}}//对窗体进行重新绘制,这将强制执行Paint事件处理程序Invalidate();}}

复制代码


2.内存法
该方法就是把图像数据直接复制到内存中,这样就使程序的运行速度大大提高。双击“内存法”按钮控件,为该控件添加Cick事件,代码如下:

复制代码

     /// <summary>/// 内存法(适用于任意大小的24位彩色图像)/// </summary>private void memory_Click(object sender, EventArgs e){if (curBitmpap != null){//位图矩形Rectangle rect = new Rectangle(0, 0, curBitmpap.Width, curBitmpap.Height);//以可读写的方式锁定全部位图像素System.Drawing.Imaging.BitmapData bmpData = curBitmpap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmpap.PixelFormat);//得到首地址IntPtr ptr = bmpData.Scan0;//定义被锁定的数组大小,由位图数据与未用空间组成的int bytes = bmpData.Stride * bmpData.Height;//定义位图数组byte[] rgbValues = new byte[bytes];//复制被锁定的位图像素值到该数组内System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);//灰度化double colorTemp = 0;for (int i = 0; i < bmpData.Height; i++){//只处理每行中是图像像素的数据,舍弃未用空间for (int j = 0; j < bmpData.Width * 3; j += 3){//利用公式计算灰度值colorTemp = rgbValues[i * bmpData.Stride + j + 2] * 0.299 + rgbValues[i * bmpData.Stride + j + 1] * 0.587 + rgbValues[i * bmpData.Stride + j] * 0.114;//R=G=BrgbValues[i * bmpData.Stride + j] = rgbValues[i * bmpData.Stride + j + 1] = rgbValues[i * bmpData.Stride + j + 2] = (byte)colorTemp;}}//把数组复制回位图System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);//解锁位图像素curBitmpap.UnlockBits(bmpData);//对窗体进行重新绘制,这将强制执行Paint事件处理程序Invalidate();}}

复制代码

3.指针法
该方法与内存法相似,开始都是通过 Lockbits方法来获取位图的首地址。但该方法更简洁,直接应用指针对位图进行操作。

为了保持类型安全,在默认情况下,C#是不支持指针运算的,因为使用指针会带来相关的风险。所以C#只允许在特别标记的代码块中使用指针。通过使用 unsafe关键字,可以定义可使用指针的不安全上下文。

双击“指针法”按钮控件,为该控件添加 Click事件,代码如下:

复制代码

     /// <summary>/// 指针法/// </summary>private void pointer_Click(object sender, EventArgs e){if (curBitmpap != null){//位图矩形Rectangle rect = new Rectangle(0, 0, curBitmpap.Width, curBitmpap.Height);//以可读写的方式锁定全部位图像素System.Drawing.Imaging.BitmapData bmpData = curBitmpap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmpap.PixelFormat);byte temp = 0;//启用不安全模式unsafe{//得到首地址byte* ptr = (byte*)(bmpData.Scan0);//二维图像循环for (int i = 0; i < bmpData.Height; i++){for (int j = 0; j < bmpData.Width; j++){//利用公式计算灰度值temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);//R=G=Bptr[0] = ptr[1] = ptr[2] = temp;//指向下一个像素ptr += 3;}//指向下一行数组的首个字节ptr += bmpData.Stride - bmpData.Width * 3;}}//解锁位图像素curBitmpap.UnlockBits(bmpData);//对窗体进行重新绘制,这将强制执行Paint事件处理程序Invalidate();}}

复制代码

由于启动了不安全模式,为了能够顺利地编译该段代码,必须设置相关选项。在主菜单中选择“项目|gray属性”,在打开的属性页中选择“生成”属性页,最后选中“允许不安全代码”复选框。

三种方法的比较

从3段代码的长度和难易程度来看,提取像素法又短又简单。它直接应用GD+中的Bitmap. Getpixel方法和 Bitmap. Setpixel方法,大大减少了代码的长度,降低了使用者的难度,并且可读性好。但衡量程序好坏的标准不是仅仅看它的长度和难易度,而是要看它的效率,尤其是像图像处理这种往往需要处理二维数据的大信息量的应用领域,就更需要考虑效率了为了比较这3种方法的效率,我们对其进行计时。首先在主窗体内添加一个 Label控件和 Textbox控件。

添加一个类:HiPerfTimer

复制代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;namespace gray
{internal class HiPerfTimer{//引用win32API中的QueryPerformanceCounter()方法//该方法用来查询任意时刻高精度计数器的实际值[DllImport("Kernel32.dll")]         //using System.Runtime.InteropServices;private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);//引用win32API中的QueryPerformanceCounter()方法//该方法用来查询任意时刻高精度计数器的实际值[DllImport("Kernel32.dll")]private static extern bool QueryPerformanceFrequency(out long lpFrequency);private long startTime, stopTime;private long freq;public HiPerfTimer(){startTime = 0;stopTime = 0;if(QueryPerformanceFrequency(out freq) == false){//不支持高性能计时器throw new Win32Exception();     //using System.ComponentModel;}}//开始计时public void Start(){//让等待线程工作Thread.Sleep(0);                //using System.Threading;QueryPerformanceCounter(out startTime);}//结束计时public void Stop(){QueryPerformanceCounter(out stopTime);}//返回计时结果(ms)public double Duration{get{return (double)(stopTime - startTime) * 1000 / (double)freq;}}}
}

复制代码

在Form1类内定义HiPerfTimer类并在构造函数内为其实例化

        private HiPerfTimer myTimer;public Form1(){InitializeComponent();myTimer = new gray.HiPerfTimer();}

分别在“提取像素法”、“内存法”和“指针法” Button控件的 Click事件程序代码内的

if判断语句之间的最开始一行添加以下代码:

            //启动计时器myTimer.Start();

在上述3个单击事件内的 Invalidate0语句之前添加以下代码:

             //关闭计时器myTimer.Stop();//在TextBox内显示计时时间timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";

最后,编译并运行该段程序。可以明显看出,内存法和指针法比提取像素法要快得多。提取像素法应用GDI+中的方法,易于理解,方法简单,很适合于C#的初学者使用,但它的运行速度最慢,效率最低。内存法把图像复制到内存中,直接对内存中的数据进行处理,速度明显提高,程序难度也不大。指针法直接应用指针来对图像进行处理,所以速度最快。但在C#中是不建议使用指针的,因为使用指针,代码不仅难以编写和调试,而且无法通过CLR的内存类型安全检查,不能发挥C#的特长。只有对C#和指针有了充分的理解,才能用好该方法。究竟要使用哪种方法,还要看具体情况而定。但3种方法都能有效地对图像进行处理。

全文代码:

复制代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace gray
{public partial class Form1 : Form{private HiPerfTimer myTimer;public Form1(){InitializeComponent();myTimer = new gray.HiPerfTimer();}//文件名private string curFileName;//图像对象private System.Drawing.Bitmap curBitmpap;/// <summary>/// 打开图像文件/// </summary>private void open_Click(object sender, EventArgs e){//创建OpenFileDialogOpenFileDialog opnDlg = new OpenFileDialog();//为图像选择一个筛选器opnDlg.Filter = "所有图像文件|*.bmp;*.pcx;*.png;*.jpg;*.gif;" +"*.tif;*.ico;*.dxf;*.cgm;*.cdr;*.wmf;*.eps;*.emf|" +"位图(*.bmp;*.jpg;*.png;...)|*.bmp;*.pcx;*.png;*.jpg;*.gif;*.tif;*.ico|" +"矢量图(*.wmf;*.eps;*.emf;...)|*.dxf;*.cgm;*.cdr;*.wmf;*.eps;*.emf";//设置对话框标题opnDlg.Title = "打开图像文件";//启用“帮助”按钮opnDlg.ShowHelp = true;//如果结果为“打开”,选定文件if(opnDlg.ShowDialog()==DialogResult.OK){//读取当前选中的文件名curFileName = opnDlg.FileName;//使用Image.FromFile创建图像对象try{curBitmpap = (Bitmap)Image.FromFile(curFileName);}catch(Exception exp){MessageBox.Show(exp.Message);}}//对窗体进行重新绘制,这将强制执行paint事件处理程序Invalidate();}private void Form1_Paint(object sender, PaintEventArgs e){//获取Graphics对象Graphics g = e.Graphics;if (curBitmpap != null){//使用DrawImage方法绘制图像//160,20:显示在主窗体内,图像左上角的坐标//curBitmpap.Width, curBitmpap.Height图像的宽度和高度g.DrawImage(curBitmpap, 160, 20, curBitmpap.Width, curBitmpap.Height);}}/// <summary>/// 保存图像文件/// </summary>private void save_Click(object sender, EventArgs e){//如果没有创建图像,则退出if (curBitmpap == null)return;//调用SaveFileDialogSaveFileDialog saveDlg = new SaveFileDialog();//设置对话框标题saveDlg.Title = "保存为";//改写已存在文件时提示用户saveDlg.OverwritePrompt = true;//为图像选择一个筛选器saveDlg.Filter = "BMP文件(*.bmp)|*.bmp|" + "Gif文件(*.gif)|*.gif|" + "JPEG文件(*.jpg)|*.jpg|" + "PNG文件(*.png)|*.png";//启用“帮助”按钮saveDlg.ShowHelp = true;//如果选择了格式,则保存图像if (saveDlg.ShowDialog() == DialogResult.OK){//获取用户选择的文件名string filename = saveDlg.FileName;string strFilExtn = filename.Remove(0, filename.Length - 3);//保存文件switch (strFilExtn){//以指定格式保存case "bmp":curBitmpap.Save(filename, System.Drawing.Imaging.ImageFormat.Bmp);break;case "jpg":curBitmpap.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg);break;case "gif":curBitmpap.Save(filename, System.Drawing.Imaging.ImageFormat.Gif);break;case "tif":curBitmpap.Save(filename, System.Drawing.Imaging.ImageFormat.Tiff);break;case "png":curBitmpap.Save(filename, System.Drawing.Imaging.ImageFormat.Png);break;default:break;}}}//关闭窗体 private void close_Click(object sender, EventArgs e){this.Close();}/// <summary>/// 提取像素法/// </summary>private void pixel_Click(object sender, EventArgs e){//启动计时器myTimer.Start();if (curBitmpap != null){Color curColor;int ret;//二维图像数组循环for(int i = 0; i < curBitmpap.Width; i++){for(int j = 0; j < curBitmpap.Height; j++){//获取该像素点的RGB颜色值curColor = curBitmpap.GetPixel(i, j);//利用公式计算灰度值ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);//设置该像素点的灰度值,R=G=B=retcurBitmpap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));}}//关闭计时器myTimer.Stop();//在TextBox内显示计时时间timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";//对窗体进行重新绘制,这将强制执行Paint事件处理程序Invalidate();}}/// <summary>/// 内存法(适用于任意大小的24位彩色图像)/// </summary>private void memory_Click(object sender, EventArgs e){//启动计时器myTimer.Start();if (curBitmpap != null){//位图矩形Rectangle rect = new Rectangle(0, 0, curBitmpap.Width, curBitmpap.Height);//以可读写的方式锁定全部位图像素System.Drawing.Imaging.BitmapData bmpData = curBitmpap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmpap.PixelFormat);//得到首地址IntPtr ptr = bmpData.Scan0;//定义被锁定的数组大小,由位图数据与未用空间组成的int bytes = bmpData.Stride * bmpData.Height;//定义位图数组byte[] rgbValues = new byte[bytes];//复制被锁定的位图像素值到该数组内System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);//灰度化double colorTemp = 0;for (int i = 0; i < bmpData.Height; i++){//只处理每行中是图像像素的数据,舍弃未用空间for (int j = 0; j < bmpData.Width * 3; j += 3){//利用公式计算灰度值colorTemp = rgbValues[i * bmpData.Stride + j + 2] * 0.299 + rgbValues[i * bmpData.Stride + j + 1] * 0.587 + rgbValues[i * bmpData.Stride + j] * 0.114;//R=G=BrgbValues[i * bmpData.Stride + j] = rgbValues[i * bmpData.Stride + j + 1] = rgbValues[i * bmpData.Stride + j + 2] = (byte)colorTemp;}}//把数组复制回位图System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);//解锁位图像素curBitmpap.UnlockBits(bmpData);//关闭计时器myTimer.Stop();//在TextBox内显示计时时间timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";//对窗体进行重新绘制,这将强制执行Paint事件处理程序Invalidate();}}/// <summary>/// 指针法/// </summary>private void pointer_Click(object sender, EventArgs e){//启动计时器myTimer.Start();if (curBitmpap != null){//位图矩形Rectangle rect = new Rectangle(0, 0, curBitmpap.Width, curBitmpap.Height);//以可读写的方式锁定全部位图像素System.Drawing.Imaging.BitmapData bmpData = curBitmpap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmpap.PixelFormat);byte temp = 0;//启用不安全模式unsafe{//得到首地址byte* ptr = (byte*)(bmpData.Scan0);//二维图像循环for (int i = 0; i < bmpData.Height; i++){for (int j = 0; j < bmpData.Width; j++){//利用公式计算灰度值temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);//R=G=Bptr[0] = ptr[1] = ptr[2] = temp;//指向下一个像素ptr += 3;}//指向下一行数组的首个字节ptr += bmpData.Stride - bmpData.Width * 3;}}//解锁位图像素curBitmpap.UnlockBits(bmpData);//关闭计时器myTimer.Stop();//在TextBox内显示计时时间timeBox.Text = myTimer.Duration.ToString("####.##") + "毫秒";//对窗体进行重新绘制,这将强制执行Paint事件处理程序Invalidate();}}/// <summary>/// 内存法(仅适用于512*512的图像)/// </summary>//private void memory_Click(object sender, EventArgs e)//{//    if (curBitmpap != null)//    {//        //位图矩形//        Rectangle rect = new Rectangle(0, 0, curBitmpap.Width, curBitmpap.Height);//        //以可读写的方式锁定全部位图像素//        System.Drawing.Imaging.BitmapData bmpData = curBitmpap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, curBitmpap.PixelFormat);//        //得到首地址//        IntPtr ptr = bmpData.Scan0;//        //24位bmp位图字节数//        int bytes = curBitmpap.Width * curBitmpap.Height * 3;//        //定义位图数组//        byte[] rgbValues = new byte[bytes];//        //复制被锁定的位图像素值到该数组内//        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);//        //灰度化//        double colorTemp = 0;//        for(int i = 0; i < rgbValues.Length; i += 3)//        {//            //利用公式计算灰度值//            colorTemp = rgbValues[i + 2] * 0.299 + rgbValues[i + 1] * 0.587 + rgbValues[i] * 0.114;//            //R=G=B//            rgbValues[i]=rgbValues[i+1]=rgbValues[i+2]=(byte)colorTemp;//        }//        //把数组复制回位图//        System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);//        //解锁位图像素//        curBitmpap.UnlockBits(bmpData);//        //对窗体进行重新绘制,这将强制执行Paint事件处理程序//        Invalidate();//    }//}}
}

复制代码

复制代码

/// <summary>/// 图像灰度化/// </summary>/// <param name="bmp"></param>/// <returns></returns>public static Bitmap ToGray(Bitmap bmp){for (int i = 0; i < bmp.Width; i++){for (int j = 0; j < bmp.Height; j++){//获取该点的像素的RGB的颜色Color color = bmp.GetPixel(i, j);//利用公式计算灰度值int gray = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);Color newColor = Color.FromArgb(gray, gray, gray);bmp.SetPixel(i, j, newColor);}}return bmp;}

复制代码

复制代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;namespace gray
{internal class HiPerfTimer{//引用win32API中的QueryPerformanceCounter()方法//该方法用来查询任意时刻高精度计数器的实际值[DllImport("Kernel32.dll")]         //using System.Runtime.InteropServices;private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);//引用win32API中的QueryPerformanceCounter()方法//该方法用来查询任意时刻高精度计数器的实际值[DllImport("Kernel32.dll")]private static extern bool QueryPerformanceFrequency(out long lpFrequency);private long startTime, stopTime;private long freq;public HiPerfTimer(){startTime = 0;stopTime = 0;if(QueryPerformanceFrequency(out freq) == false){//不支持高性能计时器throw new Win32Exception();     //using System.ComponentModel;}}//开始计时public void Start(){//让等待线程工作Thread.Sleep(0);                //using System.Threading;QueryPerformanceCounter(out startTime);}//结束计时public void Stop(){QueryPerformanceCounter(out stopTime);}//返回计时结果(ms)public double Duration{get{return (double)(stopTime - startTime) * 1000 / (double)freq;}}}
}

复制代码

灰度图像二值化
在进行了灰度化处理之后,图像中的每个象素只有一个值,那就是象素的灰度值。它的大小决定了象素的亮暗程度。为了更加便利的开展下面的图像处理操作,还需要对已经得到的灰度图像做一个二值化处理。图像的二值化就是把图像中的象素根据一定的标准分化成两种颜色。在系统中是根据象素的灰度值处理成黑白两种颜色。和灰度化相似的,图像的二值化也有很多成熟的算法。它可以采用自适应阀值法,也可以采用给定阀值法。

复制代码

     #region Otsu阈值法二值化模块   /// <summary>   /// Otsu阈值   /// </summary>   /// <param name="b">位图流</param>   /// <returns></returns>   public Bitmap OtsuThreshold(Bitmap b){// 图像灰度化   // b = Gray(b);   int width = b.Width;int height = b.Height;byte threshold = 0;int[] hist = new int[256];int AllPixelNumber = 0, PixelNumberSmall = 0, PixelNumberBig = 0;double MaxValue, AllSum = 0, SumSmall = 0, SumBig, ProbabilitySmall, ProbabilityBig, Probability;BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);unsafe{byte* p = (byte*)data.Scan0;int offset = data.Stride - width * 4;for (int j = 0; j < height; j++){for (int i = 0; i < width; i++){hist[p[0]]++;p += 4;}p += offset;}b.UnlockBits(data);}//计算灰度为I的像素出现的概率   for (int i = 0; i < 256; i++){AllSum += i * hist[i];     //   质量矩   AllPixelNumber += hist[i];  //  质量       }MaxValue = -1.0;for (int i = 0; i < 256; i++){PixelNumberSmall += hist[i];PixelNumberBig = AllPixelNumber - PixelNumberSmall;if (PixelNumberBig == 0){break;}SumSmall += i * hist[i];SumBig = AllSum - SumSmall;ProbabilitySmall = SumSmall / PixelNumberSmall;ProbabilityBig = SumBig / PixelNumberBig;Probability = PixelNumberSmall * ProbabilitySmall * ProbabilitySmall + PixelNumberBig * ProbabilityBig * ProbabilityBig;if (Probability > MaxValue){MaxValue = Probability;threshold = (byte)i;}}return this.Threshoding(b, threshold);} // end of OtsuThreshold 2  #endregion#region      固定阈值法二值化模块public Bitmap Threshoding(Bitmap b, byte threshold){int width = b.Width;int height = b.Height;BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);unsafe{byte* p = (byte*)data.Scan0;int offset = data.Stride - width * 4;byte R, G, B, gray;for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){R = p[2];G = p[1];B = p[0];gray = (byte)((R * 19595 + G * 38469 + B * 7472) >> 16);if (gray >= threshold){p[0] = p[1] = p[2] = 255;}else{p[0] = p[1] = p[2] = 0;}p += 4;}p += offset;}b.UnlockBits(data);return b;}}#endregion

复制代码

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

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

相关文章

【转】c#数字图像处理(三)灰度直方图

转自&#xff1a;https://www.cnblogs.com/dearzhoubi/p/8621804.html 灰度直方图是灰度的函数,描述的是图像中具有该灰度级的像素的个数。如果用直角坐标系来表示,则它的横坐标是灰度级,纵坐标是该灰度出现的概率(像素的个数)。 using System; using System.Collections.Gener…

电梯门禁系统服务器一般在哪,别被吓住了,电梯门禁(梯控)安装其实并不难...

电梯门禁又称梯控&#xff0c;主要用于对电梯的出入权限进入控制&#xff0c;只有授权卡在读卡器刷过后&#xff0c;才能到达指定楼层。梯控的使用越来越普遍了&#xff0c;很多人觉得梯控很神秘&#xff0c;很高不可攀&#xff0c;其实说到底它不过是门禁的一种&#xff0c;只…

【转】c#数字图像处理(四)线性点运算

转自&#xff1a;https://www.cnblogs.com/dearzhoubi/p/8622325.html 灰度图像的点运算可分为线性点运算和非线性点运算两种。 4.1线性点运算定义 线性点运算就是输出灰度级与输入灰度级呈线性关系的点运算。在这种情况下,灰度变换函数的形式为: g(x, y)pf(x,y)L 其中 f(x,…

工作人员做好项目协调服务器,项目团队协作做好三件事

原标题&#xff1a; 项目团队协作做好三件事大家也许在小时候就听过三个和尚的故事&#xff1a;当庙里有一个和尚时&#xff0c;他一切自己做主&#xff0c;做得很自在;当庙里有两个和尚时&#xff0c;他们通过协商可以自觉地进行分工合作&#xff0c;同样做的不错;可当庙里来了…

给vc6插上翅膀

最重要的当然是VC助手了。。我比较喜欢低版本的Visual.Assist.v6.0.0.1079.zip&#xff0c;环保类型的 但无奈我的vs2005也想使用这个插件&#xff0c;所以我选择了VisualAssistXv10&#xff0c;目前装的是Visual.Assist.X.10.4.1626.0 以前还用过一些版本很奇怪的&#xff0c;…

【转】[程序集清单定义与程序集引用不匹配]分析及解决

转自&#xff1a;https://www.cnblogs.com/shuangzimuchangzhu/p/8572817.html 什么是程序集清单(Assembly Manifest)? 我们知道&#xff0c;在.net中。程序是以程序集为单位进行打包的&#xff0c;通常一个.exe文件或一个.dll文件就是一个程序集。程序集一般包含了以下几个部…

dos如何修改远程服务器的密码,dos命令登入远程服务器

dos命令登入远程服务器 内容精选换一换远程桌面链接Windows云服务器报错&#xff1a;连接被拒绝&#xff0c;因为没有授权此用户账户进行远程登录。Windows远程桌面相关权限配置异常。在运行窗口输入secpol.msc&#xff0c;打开组策略编辑器打开"本地策略 > 用户权限分…

设计模式C++实现 ——状态模式

软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性&#xff1a;封装、继承、多态&#xff0c;真正领悟设计模式的精髓是可能一个漫长的过程&#xff0c;需要大量实践经验的积累。最近看设计模式的书&#xff0…

【转】正确认识动脉压力波形

转自&#xff1a;https://www.sohu.com/a/288192545_377325 前言 早在50多年前&#xff0c;就已经在麻醉患者中开始进行直接动脉血压监测。尽管对动脉压力波形的形态和细节进行分析可以给我们提供一些有用的诊断信息&#xff0c;但现代的医生似乎很少关注它。临床实践中的这些…

2008服务器ftp上传文件,win2008怎么开通服务器ftp上传

win2008怎么开通服务器ftp上传 内容精选换一换GPU加速型实例如需使用OpenGL/DirectX/Vulcan等图形加速能力则需要安装GRID驱动并自行购买和配置使用GRID License。此外&#xff0c;GRID驱动配合vDWS类型License&#xff0c;也支持CUDA&#xff0c;用来满足既需要计算加速也需要…

【转】DICOM中几个判断图像方向的tag

转自&#xff1a;https://www.cnblogs.com/h2zZhou/p/9072967.html 在DICOM标准里&#xff0c;有三个TAG与成像的方向相关。 参考来源&#xff1a;Kitware关于DICOM方向的说明 http://public.kitware.com/IGSTKWIKI/index.php/DICOM_data_orientation 包括 1、Image Positi…

学习 SQL 语句 - Select(4): 排序

Order By Asc|Desc本例效果图:代码文件:unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ExtCtrls, Grids, DBGrids, DB, ADODB;typeTForm1 class(TForm)DBGrid1: TDBGrid;DataSource1: TDataSource;…

【转】Ubuntu 16.04 远程桌面

转自&#xff1a;实现Windows直接远程访问Ubuntu 18.04&#xff08;旧版本也支持,无需安装第三方桌面,直接使用自带远程工具&#xff09; - 法号阿兴 - 博客园 一、设置Ubuntu 16.04 允许进行远程控制 首先&#xff0c;我们先设置Ubuntu的远程控制&#xff0c;将其设置为允许被…

GridView应用整理

2009年5月31日下午 21:58:38 获取GridView中RowCommand的当前选中行索引 <asp:GridView ID"BookGridView" runat"server"><Columns><asp:BoundField DataField"id" HeaderText"图书编号" /><asp:BoundField Data…

【转】Ubuntu下使用sysv-rc-conf管理服务

转自&#xff1a;https://www.linuxidc.com/Linux/2016-11/136834.htm sysv-rc-conf简介 sysv-rc-conf是一个强大的服务管理程序&#xff0c;群众的意见是sysv-rc-conf比chkconfig、rcconf好用。 背景知识 Ubuntu运行级别 Linux 系统任何时候都运行在一个指定的运行级上&…

【转】How to install VNC server on ubuntu 14.04

转自&#xff1a;https://www.krizna.com/ubuntu/install-vnc-server-ubuntu-14-04/ VNC server is used to share graphical desktop which can be controlled from other computers . This guide is helpful to install VNC server on Ubuntu Desktop 14.04, Ubuntu server …

Nsis 使用1-- 依条件显示自定义页面 custom page on condition

在制作安装程序的时候&#xff0c;我们会经常遇到根据用户的不同选择而随后显示不同的安装信息采集页面。 其实很简单&#xff0c;在使用NSIS的时候发现了这么个方法&#xff0c;记下来防止自己忘记哈&#xff1a;Code; MUI 2 compatible ------!include "MUI2.nsh"!…

WINCE6.0操作系统---内核(kernel)学习

备注&#xff1a;这里的内核指kernel&#xff0c;其表现形式为kernel.dll&#xff0c;OS指操作系统&#xff0c;core指核心。 图1 WINCE6.0体系结构 1. kernel的组成和功能 WINCE6.0操作系统内(kernel)在代码中的表现形式是kernel.dll(也就是kern.dll)&#xff0c; WINCE5…

WINCE6.0体系结构学习

WINCE6.0的体系结构图如下图所示&#xff1a; 图1 WINCE的体系结构 根据上图可以把WINCE6.0体系结构分为硬件层、OEM层、操作系统层和应用层&#xff0c;这四层紧密合作&#xff0c;相互配合来完成从应用程序的调用到对硬件的操作和交互。 1. 硬件层 硬件平台的核心是嵌入…

【转】深度理解C# 的执行原理

转自&#xff1a;https://zhuanlan.zhihu.com/p/47177008 从编译原理说起虚拟机是什么C# 是什么&#xff0c;IL 又是什么.Net Framework vs MonoUnity3D 中的 C#小结作者&#xff1a;易立 | 腾讯IEG高级工程师为什么 Unity3D 可以运行 C#&#xff0c;C# 和 Mono 是什么关系&am…