解决ZXing.net二维码识别率低的问题
c#.net调用zxing识别二维码,有时候成功率比微信扫码低很多,尝试解决了一些,效果还行。
网上说用商业花钱买的那个,我没试,不知道效果怎么样。
using AForge.Imaging.Filters;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Windows.Forms;
using ZXing;
using ZXing.Common;
//
//using AForge.Imaging;
//using AForge.Imaging.Filters;
namespace iPublic.识别
{
/// <summary>
/// 二维码识别
/// 依赖ZXing
/// 修改记录:
/// 2025-01-19, 海宏软件
/// </summary>
public static class QRCodeReader
{
/// <summary>
/// 识别发票(BMP 图像文件)二维码
/// 修改记录:
/// 2025-02-06, 海宏软件, 首先识别全图,如果没有识别成功,然后识别上下左右切分成多块,2分、3分.然后是灰度、黑白二值化
/// </summary>
/// <param name="imagePath"></param>
/// <returns></returns>
public static string ReadQRCode(string imagePath)
{ return ReadQRCode(new Bitmap(imagePath)); }
public static string ReadQRCode(Bitmap ABitmap)
{
ZXing.Result result = null;
DateTime dBegin = DateTime.Now;
Bitmap bitmap = ABitmap;
// 创建一个BarcodeReader实例,设置解码选项
var options = new DecodingOptions
{
// 核心参数配置
CharacterSet = "UTF-8", // 解决中文乱码:ml-citation{ref="3,5" data="citationList"}
TryHarder = true, // 启用深度扫描模式:ml-citation{ref="5" data="citationList"}
//PureBarcode = false, // 允许非纯条形码图像false
// 专用二维码参数
PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.QR_CODE },
// 图像增强参数
UseCode39ExtendedMode = true,
UseCode39RelaxedExtendedMode = true
};
var barcodeReader = new BarcodeReader
{
Options = options,
AutoRotate = true, // 自动旋转识别:ml-citation{ref="4" data="citationList"}
TryInverted = true // 尝试反转色识别
};
// 尝试识别原图,如果识别到二维码,返回识别的条码内容
result = 尝试识别(barcodeReader, bitmap, "0"); //, true, false, false
if (result != null) return result.Text;
////第二种识别方式ZBar:原文链接:https://blog.csdn.net/fuzhenglai/article/details/103732113
//using (ZBar.ImageScanner scanner = new ZBar.ImageScanner())
//{
// var symbols = scanner.Scan(bitmap);
// if (symbols.Count > 0 && symbols[0].Data.Length > 8)
// {
// result.DataView = symbols[0].Data;
// result.Code = Enum.ResultCode.DealSuccess;
// result.Message = "识别成功";
// return ReturnResp(result);
// }
//}
// 如果没有识别到二维码,按照上下左右四个区域分别进行识别
int width = ABitmap.Width;
int height = ABitmap.Height;
int halfWidth = width / 2;
int halfHeight = height / 2;
Rectangle[] regions = new Rectangle[]
{
//2分法:上中下
new Rectangle(halfWidth, 0, halfWidth, halfHeight), // 上右1
new Rectangle(0, 0, halfWidth, halfHeight), // 上左0
new Rectangle(0, halfHeight, halfWidth, halfHeight), // 下左2
new Rectangle(halfWidth, halfHeight, halfWidth, halfHeight), // 下右3
//3分法:上
new Rectangle(2*width/3,0,width/3,height/3), // 右上角2
new Rectangle(0,0,width/3,height/3), // 左上角0
new Rectangle(width/3,0,width/3,height/3), // 上中1
//3分法:中
new Rectangle(0,2*height/3,width/3,height/3), // 左下角
new Rectangle(width/3,2*height/3,width/3,height/3), // 下中
new Rectangle(2*width/3,2*height/3,width/3,height/3), // 右下角
//3分法:下
new Rectangle(0,height/3,width/3,height/3), // 左中
new Rectangle(width/3,height/3,width/3,height/3), // 中中
new Rectangle(2*width/3,height/3,width/3,height/3), // 右中
};
for (int i = 0; i < regions.Length; i++)
{
var region = regions[i];
using (var bitmapRegion = ABitmap.Clone(region, ABitmap.PixelFormat))
{
result = 尝试识别(barcodeReader, bitmapRegion, (i + 1).ToString() + "x" + region.Left + "y" + region.Top + "w" + region.Width + "h" + region.Height);
if (result != null) return result.Text;
}
}
//最后再来尝试原图的512和黑白二值化
//result = 尝试识别(barcodeReader, bitmap, "99", false, true, true);
// 如果所有区域都没有识别到二维码,返回空字符串
return string.Empty;
}
private static Result 尝试识别(BarcodeReader barcodeReader, Bitmap ABitmap, string 备注 = "",
bool 尝试原图 = true, bool 尝试512像素 = true, bool 尝试黑白二值化 = true)
{
string s = "", sDir = "", sFile = "", sClass = "QRCodeReader.尝试识别", sDebug = "";
Bitmap bitmap = new Bitmap(ABitmap); //ABitmap
ZXing.Result result = null;
try
{
if (尝试原图)
{
result = barcodeReader.Decode(bitmap);
if (result != null && !string.IsNullOrEmpty(result.Text)) return result;
ZXing.Result[] results = barcodeReader.DecodeMultiple(bitmap);
if (results != null && results.Length > 0 && !string.IsNullOrEmpty(results[0].Text)) return results[0];
saveTempImage(bitmap, 备注 + "原图");
}
////如果识别不了,尝试转成512
//if (尝试512像素 && bitmap.Width > 512)
//{
// bitmap = 优化图片尺寸(ABitmap);
// result = barcodeReader.Decode(bitmap);
// if (result != null && !string.IsNullOrEmpty(result.Text)) return result;
// saveTempImage(bitmap, 备注 + "调整512像素");
// //再尝试灰度优化512的
// if (尝试黑白二值化)
// {
// bitmap = 灰度优化图片_点阵(bitmap);
// bitmap = AForge二值化图片_Auto(bitmap); //二值化图片_原生、AForge二值化图片、AForge二值化图片_Auto
// result = barcodeReader.Decode(bitmap);
// if (result != null && !string.IsNullOrEmpty(result.Text)) return result;
// saveTempImage(bitmap, 备注 + "调整512后二值化");
// }
//}
//再尝试灰度优化原图
if (尝试黑白二值化)
{
bitmap = 灰度优化图片_点阵(ABitmap); //灰度优化图片
bitmap = AForge二值化图片_Auto(bitmap); //二值化图片_原生、AForge二值化图片、AForge二值化图片_Auto
result = barcodeReader.Decode(bitmap);
saveTempImage(bitmap, 备注 + "原图二值化");
}
}
catch (Exception x)
{
iLog.Info(sClass, x.Message + ".\r\n" + x.StackTrace);
}
return result;
}
private static Bitmap AForge二值化图片(Bitmap original, int threshold = 128)
{
// 灰度转换
Grayscale grayscale = new Grayscale(0.2125, 0.587, 0.114);
//grayscale = new Grayscale(255, 255, 255);
Bitmap gray = grayscale.Apply(original);
// 二值化强化
var thresholdFilter = new Threshold(threshold);
return thresholdFilter.Apply(gray);
}
//参考:https://blog.csdn.net/weixin_33858249/article/details/94550512
private static Bitmap AForge二值化图片_Auto(Bitmap original)
{
int[] histogram = new int[256];
int minGrayValue = 255, maxGrayValue = 0;
int threshold = -1, newThreshold=0;
Bitmap bitmap = new Bitmap(original);
string s = "", sClass = "QRCodeReader.AForge二值化图片_Auto", sDebug = "";
try
{
//求取直方图
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
Color pixelColor = bitmap.GetPixel(i, j);
histogram[pixelColor.R]++;
if (pixelColor.R > maxGrayValue) maxGrayValue = pixelColor.R;
if (pixelColor.R < minGrayValue) minGrayValue = pixelColor.R;
}
}
//迭代计算阀值
newThreshold = (minGrayValue + maxGrayValue) / 2;
for (int iterationTimes = 0; threshold != newThreshold && iterationTimes < 100; iterationTimes++)
{
threshold = newThreshold;
int lP1 = 0;
int lP2 = 0;
int lS1 = 0;
int lS2 = 0;
//求两个区域的灰度的平均值
for (int i = minGrayValue; i < threshold; i++)
{
lP1 += histogram[i] * i;
lS1 += histogram[i];
}
int mean1GrayValue = (lP1 / lS1);
for (int i = threshold + 1; i < maxGrayValue; i++)
{
lP2 += histogram[i] * i;
lS2 += histogram[i];
}
int mean2GrayValue = (lP2 / lS2);
newThreshold = (mean1GrayValue + mean2GrayValue) / 2;
}
//计算二值化
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
Color pixelColor = bitmap.GetPixel(i, j);
if (pixelColor.R > threshold) bitmap.SetPixel(i, j, Color.FromArgb(255, 255, 255));
else bitmap.SetPixel(i, j, Color.FromArgb(0, 0, 0));
}
}
////用AForge的二值化强化
//AForge二值化图片(bitmap, threshold);
}
catch (Exception x)
{
iLog.Info(sClass, x.Message + ".\r\n" + x.StackTrace);
}
return bitmap;
}
// 灰度化+二值化(纯System.Drawing实现)
private static Bitmap 二值化图片_原生(Bitmap original, int threshold = 128)
{
//0.2125, 0.587, 0.114
var gray = new Bitmap(original.Width, original.Height);
for (int y = 0; y < original.Height; y++)
{
for (int x = 0; x < original.Width; x++)
{
Color c = original.GetPixel(x, y);
int grayValue = (int)(c.R * 0.2125 + c.G * 0.587 + c.B * 0.114);
gray.SetPixel(x, y, Color.FromArgb(grayValue, grayValue, grayValue));
}
}
// 二值化
var binary = new Bitmap(gray.Width, gray.Height);
for (int y = 0; y < gray.Height; y++)
{
for (int x = 0; x < gray.Width; x++)
{
int v = gray.GetPixel(x, y).R > threshold ? 255 : 0;
binary.SetPixel(x, y, Color.FromArgb(v, v, v));
}
}
return binary;
}
//参考:https://blog.csdn.net/weixin_33858249/article/details/94550512
private static Bitmap 灰度优化图片_点阵(Bitmap original)
{
Bitmap bitmap = original;
string s = "", sClass = "QRCodeReader.灰度优化图片_点阵", sDebug = "";
try
{
for (int i = 0; i < bitmap.Width; i++)
{
for (int j = 0; j < bitmap.Height; j++)
{
Color pixelColor = bitmap.GetPixel(i, j);
//计算灰度值.0.2125, 0.587, 0.114
int grey = (int)(0.299 * pixelColor.R + 0.587 * pixelColor.G + 0.114 * pixelColor.B);
Color newColor = Color.FromArgb(grey, grey, grey);
bitmap.SetPixel(i, j, newColor);
}
}
}
catch (Exception x)
{
iLog.Info(sClass, x.Message + ".\r\n" + x.StackTrace + "");
}
return bitmap;
}
// 灰度转换
public static Bitmap 灰度优化图片(Bitmap source)
{
Bitmap newBitmap = new Bitmap(source.Width, source.Height);
using (Graphics g = Graphics.FromImage(newBitmap))
{
ColorMatrix colorMatrix = new ColorMatrix(new float[][] {
new float[] {.3f, .3f, .3f, 0, 0},
new float[] {.59f, .59f, .59f, 0, 0},
new float[] {.11f, .11f, .11f, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}
});
using (ImageAttributes attributes = new ImageAttributes())
{
attributes.SetColorMatrix(colorMatrix);
g.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height),
0, 0, source.Width, source.Height, GraphicsUnit.Pixel, attributes);
}
}
return newBitmap;
}
public static Bitmap 优化图片尺寸(Bitmap original, int targetWidth = 512)
{ //将图像宽度固定为 512px(经验证的最佳尺寸),高度按比例缩放
//int width = Math.Min(original.Width, targetWidth);
//int height = (int)(original.Height * (width / (double)original.Width));
//return new Bitmap(original, width, height);
string s = "", sClass = "QRCodeReader.优化图片尺寸", sDebug = "";
Bitmap bitmap = original, result = null;
double zoomMultiple = 1;
int toWidth = targetWidth, toHeight = original.Height;
try
{
zoomMultiple = Convert.ToDouble(targetWidth) / Convert.ToDouble(original.Width);
toHeight = Convert.ToInt32(original.Height * zoomMultiple);
result = new Bitmap(toWidth, toHeight);
using (Graphics g = Graphics.FromImage(result))
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.Clear(Color.Transparent);
g.DrawImage(bitmap,
new Rectangle(0, 0, toWidth, toHeight),
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
GraphicsUnit.Pixel);
}
}
catch (Exception x)
{
iLog.Info(sClass, x.Message + ".\r\n" + x.StackTrace);
}
return result;
}
private static string saveTempImage(Bitmap bitmap, string 名称附加)
{
return "";
string s = "", sDir = "D:\\Temp\\" + DateTime.Now.ToString("yyyyMMdd") + "\\", sFile = DateTime.Now.ToString("yyyyMMdd_HHmmss");
if (!Directory.Exists(sDir)) Directory.CreateDirectory(sDir);
sFile += DateTime.Now.ToString("fffffff") + "_" + (new Random().Next(10000).ToString().PadLeft(4, '0')) + "#" + 名称附加 + ".bmp";
bitmap.Save(s = sDir + sFile, bitmap.RawFormat);
return s;
}
}
}

浙公网安备 33010602011771号