将Rgb图像转换为灰度C#代码时出现性能问题
我正在为Tesseract Ocr编写一个.Net包装器,如果我使用灰度图像而不是rgb图像作为输入文件,那么结果非常好 所以我在网上搜索C#解决方案,将Rgb图像转换为灰度图像,然后 这将执行3个操作以提高tesseract的精度将Rgb图像转换为灰度C#代码时出现性能问题,c#,tesseract,grayscale,C#,Tesseract,Grayscale,我正在为Tesseract Ocr编写一个.Net包装器,如果我使用灰度图像而不是rgb图像作为输入文件,那么结果非常好 所以我在网上搜索C#解决方案,将Rgb图像转换为灰度图像,然后 这将执行3个操作以提高tesseract的精度 调整图像大小 然后转换成灰度图像,去除图像中的噪声 现在,这张转换后的图像给出了几乎90%的准确结果 //Resize public Bitmap Resize(Bitmap bmp, int newWidth, int newHeight) {
//Resize
public Bitmap Resize(Bitmap bmp, int newWidth, int newHeight)
{
Bitmap temp = (Bitmap)bmp;
Bitmap bmap = new Bitmap(newWidth, newHeight, temp.PixelFormat);
double nWidthFactor = (double)temp.Width / (double)newWidth;
double nHeightFactor = (double)temp.Height / (double)newHeight;
double fx, fy, nx, ny;
int cx, cy, fr_x, fr_y;
Color color1 = new Color();
Color color2 = new Color();
Color color3 = new Color();
Color color4 = new Color();
byte nRed, nGreen, nBlue;
byte bp1, bp2;
for (int x = 0; x < bmap.Width; ++x)
{
for (int y = 0; y < bmap.Height; ++y)
{
fr_x = (int)Math.Floor(x * nWidthFactor);
fr_y = (int)Math.Floor(y * nHeightFactor);
cx = fr_x + 1;
if (cx >= temp.Width)
cx = fr_x;
cy = fr_y + 1;
if (cy >= temp.Height)
cy = fr_y;
fx = x * nWidthFactor - fr_x;
fy = y * nHeightFactor - fr_y;
nx = 1.0 - fx;
ny = 1.0 - fy;
color1 = temp.GetPixel(fr_x, fr_y);
color2 = temp.GetPixel(cx, fr_y);
color3 = temp.GetPixel(fr_x, cy);
color4 = temp.GetPixel(cx, cy);
// Blue
bp1 = (byte)(nx * color1.B + fx * color2.B);
bp2 = (byte)(nx * color3.B + fx * color4.B);
nBlue = (byte)(ny * (double)(bp1) + fy * (double)(bp2));
// Green
bp1 = (byte)(nx * color1.G + fx * color2.G);
bp2 = (byte)(nx * color3.G + fx * color4.G);
nGreen = (byte)(ny * (double)(bp1) + fy * (double)(bp2));
// Red
bp1 = (byte)(nx * color1.R + fx * color2.R);
bp2 = (byte)(nx * color3.R + fx * color4.R);
nRed = (byte)(ny * (double)(bp1) + fy * (double)(bp2));
bmap.SetPixel(x, y, System.Drawing.Color.FromArgb(255, nRed, nGreen, nBlue));
}
}
//here i included the below to functions logic without the for loop to remove repetitive use of for loop but it did not work and taking the same time.
bmap = SetGrayscale(bmap);
bmap = RemoveNoise(bmap);
return bmap;
}
//SetGrayscale
public Bitmap SetGrayscale(Bitmap img)
{
Bitmap temp = (Bitmap)img;
Bitmap bmap = (Bitmap)temp.Clone();
Color c;
for (int i = 0; i < bmap.Width; i++)
{
for (int j = 0; j < bmap.Height; j++)
{
c = bmap.GetPixel(i, j);
byte gray = (byte)(.299 * c.R + .587 * c.G + .114 * c.B);
bmap.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
}
}
return (Bitmap)bmap.Clone();
}
//RemoveNoise
public Bitmap RemoveNoise(Bitmap bmap)
{
for (var x = 0; x < bmap.Width; x++)
{
for (var y = 0; y < bmap.Height; y++)
{
var pixel = bmap.GetPixel(x, y);
if (pixel.R < 162 && pixel.G < 162 && pixel.B < 162)
bmap.SetPixel(x, y, Color.Black);
}
}
for (var x = 0; x < bmap.Width; x++)
{
for (var y = 0; y < bmap.Height; y++)
{
var pixel = bmap.GetPixel(x, y);
if (pixel.R > 162 && pixel.G > 162 && pixel.B > 162)
bmap.SetPixel(x, y, Color.White);
}
}
return bmap;
}
//调整大小
公共位图调整大小(位图bmp、int newWidth、int newHeight)
{
位图温度=(位图)bmp;
位图bmap=新位图(新宽度、新高度、临时像素格式);
双nWidthFactor=(双)临时宽度/(双)新宽度;
双N权重系数=(双)温度高度/(双)新高度;
纽约州纽约州财政部双倍外汇;
int-cx,cy,fr_x,fr_y;
颜色1=新颜色();
颜色2=新颜色();
Color color3=新颜色();
Color color4=新颜色();
字节nRed、nGreen、nBlue;
字节bp1,bp2;
对于(int x=0;x=温度宽度)
cx=fr_x;
cy=fr_y+1;
如果(cy>=温度高度)
cy=fr_y;
fx=x*nWidthFactor-fr_x;
fy=y*n权重因子-fr_y;
nx=1.0-fx;
ny=1.0-fy;
color1=温度获取像素(fr_x,fr_y);
color2=温度获取像素(cx,fr_y);
color3=温度获取像素(fr_x,cy);
color4=温度获取像素(cx,cy);
//蓝色的
bp1=(字节)(nx*color1.B+fx*color2.B);
bp2=(字节)(nx*color3.B+fx*color4.B);
nBlue=(字节)(ny*(双字节)(bp1)+fy*(双字节)(bp2));
//绿色的
bp1=(字节)(nx*color1.G+fx*color2.G);
bp2=(字节)(nx*color3.G+fx*color4.G);
nGreen=(字节)(ny*(双字节)(bp1)+fy*(双字节)(bp2));
//红色的
bp1=(字节)(nx*color1.R+fx*color2.R);
bp2=(字节)(nx*color3.R+fx*color4.R);
nRed=(字节)(ny*(双字节)(bp1)+fy*(双字节)(bp2));
bmap.SetPixel(x,y,System.Drawing.Color.FromArgb(255,nRed,nGreen,nBlue));
}
}
//在这里,我在没有for循环的情况下加入了下面的to函数逻辑,以消除for循环的重复使用,但它不起作用,并且占用了相同的时间。
bmap=设置灰度(bmap);
bmap=清除噪声(bmap);
返回bmap;
}
//设定灰度
公共位图设置灰度(位图img)
{
位图温度=(位图)img;
位图bmap=(位图)临时克隆();
颜色c;
对于(int i=0;i162&&pixel.G>162&&pixel.B>162)
bmap.SetPixel(x,y,彩色,白色);
}
}
返回bmap;
}
但问题是转换它需要很多时间
所以我加入了SetGrayscale(位图bmap)
RemoveNoise(位图bmap)
在Resize()
方法中的函数逻辑,以消除for循环的重复使用
但是它并没有解决我的问题。位图类的
GetPixel()
和SetPixel()
方法对于多次读取/写入速度非常慢。访问和设置位图中单个像素的更快方法是首先锁定它
有一个很好的例子说明了如何做到这一点,它使用了一个很好的类lockedbimat
来包装陌生人Marshal
ing代码
基本上,它所做的是使用Bitmap
类中的LockBits()
方法,为要锁定的位图区域传递一个矩形,然后将这些像素从其非托管内存位置复制到托管内存位置,以便于访问
下面是一个示例,说明如何将该示例类用于SetGrayscale()
方法:
public Bitmap SetGrayscale(Bitmap img)
{
LockedBitmap lockedBmp = new LockedBitmap(img.Clone());
lockedBmp.LockBits(); // lock the bits for faster access
Color c;
for (int i = 0; i < lockedBmp.Width; i++)
{
for (int j = 0; j < lockedBmp.Height; j++)
{
c = lockedBmp.GetPixel(i, j);
byte gray = (byte)(.299 * c.R + .587 * c.G + .114 * c.B);
lockedBmp.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
}
}
lockedBmp.UnlockBits(); // remember to release resources
return lockedBmp.Bitmap; // return the bitmap (you don't need to clone it again, that's already been done).
}
公共位图设置灰度(位图img)
{
LockedBitmap lockedBmp=新的LockedBitmap(img.Clone());
lockedBmp.LockBits();//锁定位以加快访问速度
颜色c;
对于(int i=0;i
这个包装类为我节省了大量位图处理时间。一旦您在所有方法中实现了这一点,最好只调用一次LockBits()
,那么我相信您的应用程序的性能将大大提高
我还看到你经常克隆图像。这可能不是