c#扫描图片去黑边(扫描仪去黑边)
自动去除图像扫描黑边
/// <summary>
/// 自动去除图像扫描黑边
/// </summary>
/// <param name="filename"></param>
public static void autocutblackedge(string filename)
{
//打开图像
bitmap bmp = openimage(filename);
removeblackedge(bmp);
//保存图像
saveimage(bmp, filename);
}
private static byte[] rgbvalues; // 目标数组内存
/// <summary>
/// 图像去黑边
/// </summary>
/// <param name="bmp"></param>
/// <returns></returns>
private static bitmap removeblackedge(bitmap bmp)
{
rectangle rect = new rectangle(0, 0, bmp.width, bmp.height);
bitmapdata bmpdata = bmp.lockbits(rect, imagelockmode.readwrite, bmp.pixelformat);
// 获取图像参数
int w = bmpdata.width;
int h = bmpdata.height;
int stride = bmpdata.stride; // 扫描线的宽度
double picbytesize = getpicbytesize(bmp.pixelformat);
int bwidth = (int)math.ceiling(picbytesize * w); //显示宽度
int offset = stride - bwidth; // 显示宽度与扫描线宽度的间隙
intptr ptr = bmpdata.scan0; // 获取bmpdata的内存起始位置
int scanbytes = stride * h; // 用stride宽度,表示这是内存区域的大小
// 分别设置两个位置指针,指向源数组和目标数组
int posscan = 0;
rgbvalues = new byte[scanbytes]; // 为目标数组分配内存
marshal.copy(ptr, rgbvalues, 0, scanbytes); // 将图像数据拷贝到rgbvalues中
bool ispass = true;
int i = 0, j = 0;
int cutw = (int)(bwidth * 0.02); //2%宽度(可修改)
int cuth = (int)(h * 0.02); //2%高度(可修改)
int poslen = (int)(picbytesize * 8); //继续查找深度为8的倍数(可修改)
//左边
for (i = 0; i < h; i++)
{
for (j = 0; j < bwidth; j++)
{
ispass = true;
if (rgbvalues[posscan] < 255) rgbvalues[posscan] = 255;
if (rgbvalues[posscan + 1] == 255)
{
for (int m = 1; m <= poslen; m++)
{
if (rgbvalues[posscan + m] < 255) ispass = false;
}
}
if (rgbvalues[posscan + 1] < 255 || bwidth / 2 < j) ispass = false;
reccheck(ref rgbvalues, posscan, h, stride, true);
posscan++;
if (j >= cutw && ispass) break;
}
// 跳过图像数据每行未用空间的字节,length = stride - width * byteperpixel
if (j == bwidth) posscan += offset;
else posscan += (offset + bwidth - j - 1);
}
//右边
posscan = scanbytes - 1;
for (i = h - 1; i >= 0; i--)
{
posscan -= offset;
for (j = bwidth - 1; j >= 0; j--)
{
ispass = true;
if (rgbvalues[posscan] < 255) rgbvalues[posscan] = 255;
if (rgbvalues[posscan - 1] == 255)
{
for (int m = 1; m <= poslen; m++)
{
if (rgbvalues[posscan - m] < 255) ispass = false;
}
}
if (rgbvalues[posscan - 1] < 255 || bwidth / 2 > j) ispass = false;
reccheck(ref rgbvalues, posscan, h, stride, false);
posscan--;
if (cuth < (h - i))
if (j < (bwidth - cutw) && ispass) break;
}
// 跳过图像数据每行未用空间的字节,length = stride - width * byteperpixel
if (j != -1) posscan -= j;
}
// 内存解锁
marshal.copy(rgbvalues, 0, ptr, scanbytes);
bmp.unlockbits(bmpdata); // 解锁内存区域
return bmp;
}
/// <summary>
/// 上下去除黑边时,临近黑点去除
/// </summary>
/// <param name="rgbvalues"></param>
/// <param name="posscan"></param>
/// <param name="h"></param>
/// <param name="stride"></param>
/// <param name="islleft"></param>
private static void reccheck(ref byte[] rgbvalues, int posscan, int h, int stride, bool islleft)
{
int scanbytes = h * stride;
int cuth = (int)(h * 0.01); //临近最大1%高度(可修改)
for (int i = 1; i <= cuth; i++)
{
int befrow = 0;
if (islleft && (posscan - stride * i) > 0)
{
befrow = posscan - stride * i;
}
else if (!islleft && (posscan + stride * i) < scanbytes)
{
befrow = posscan + stride * i;
}
if (rgbvalues[befrow] < 255) rgbvalues[befrow] = 255;
else break;
}
}
下一篇: C#操作FTP出现500错误解决办法