效果图,简单的还行,复杂的。。。拉跨
懒得写讲解了,全部源码直接上吧
/// <summary>/// 验证码识别/// </summary>public partial class FrmCodeIdentify : FrmBase{private string _filePath;// 原图像Image<Bgr, byte> inputImage;// 灰度图像Image<Gray, byte> inputGray;// 二值化图像Image<Gray, byte> binaryImage;// 去噪音图像Image<Gray, byte> denoisingImage;// 修复图像Image<Gray, byte> repairImage;// 图像增强Image<Bgr, byte> enhanceImage;public FrmCodeIdentify(){InitializeComponent();}/// <summary>/// 选择图像/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button1_Click(object sender, EventArgs e){using OpenFileDialog openFileDialog = new OpenFileDialog();openFileDialog.Filter = ImageExtension;if (openFileDialog.ShowDialog() == DialogResult.OK){string selectedFile = openFileDialog.FileName;_filePath = selectedFile;this.pictureBox1.Image?.Dispose();this.pictureBox1.Image = new Bitmap(_filePath);inputImage?.Dispose();inputImage = new Image<Bgr, byte>(_filePath);if (checkBox1.Checked){ImageEnhancement();Grayscale();Binarization();Denoising();RepairImage();ShowAllTxt();}else{var bitmap = inputImage.ToBitmap();ShowTxt(bitmap, label3);}}}private void ShowAllTxt(){var bitmap3 = inputImage.ToBitmap();ShowTxt(bitmap3, label3);var bitmap4 = enhanceImage.ToBitmap();ShowTxt(bitmap4, label4);var bitmap5 = inputGray.ToBitmap();ShowTxt(bitmap5, label5);var bitmap1 = binaryImage.ToBitmap();ShowTxt(bitmap1, label1);var bitmap6 = denoisingImage.ToBitmap();ShowTxt(bitmap6, label6);var bitmap7 = repairImage.ToBitmap();ShowTxt(bitmap7, label7);}private void ShowTxt(Bitmap bitmap, Label label){var data = BitmapToByteArray(bitmap);bitmap.Dispose();var txt = ExtractedText(data);label.Text = $"识别结果:{txt}";}private void FrmCodeIdentify_Load(object sender, EventArgs e){}private void FrmCodeIdentify_FormClosing(object sender, FormClosingEventArgs e){repairImage?.Dispose();enhanceImage?.Dispose();denoisingImage?.Dispose();binaryImage?.Dispose();inputImage?.Dispose();inputGray?.Dispose();engine?.Dispose();this.Dispose();}/// <summary>/// 灰度化/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button2_Click(object sender, EventArgs e){Grayscale();var bitmap5 = inputGray.ToBitmap();ShowTxt(bitmap5, label5);}private void Grayscale(){inputGray?.Dispose();if (string.IsNullOrEmpty(_filePath)){MessageBox.Show("请选择图像");return;}//using Matrix<float> kernel = new Matrix<float>(kernelData);// 应用卷积操作//CvInvoke.Filter2D(inputImage, inputImage, kernel, new Point(-1, -1));//ShowPictureBox(pictureBox1, inputImage);//inputImage = PerformTextCorrection(inputImage);inputGray = enhanceImage.Convert<Gray, byte>();// 应用直方图均衡化//inputGray._EqualizeHist();this.pictureBox2.Image?.Dispose();this.pictureBox2.Image = inputGray.ToBitmap();}/// <summary>/// 二值化/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button3_Click(object sender, EventArgs e){Binarization();var bitmap1 = binaryImage.ToBitmap();ShowTxt(bitmap1, label1);}private void Binarization(){if (inputGray == null){MessageBox.Show("需要灰度化图像");return;}binaryImage?.Dispose();using var inputGrayOut = new Image<Gray, byte>(inputGray.Size);// 自适应阈值//binaryImage= new Image<Gray, byte>(inputGray.Size);//CvInvoke.AdaptiveThreshold(inputGray, binaryImage, 255, AdaptiveThresholdType.MeanC, ThresholdType.Binary, 11, 2);// 计算OTSU阈值var threshold = CvInvoke.Threshold(inputGray, inputGrayOut, 0, 255, ThresholdType.BinaryInv | ThresholdType.Otsu);// 二值化图像binaryImage = inputGrayOut.ThresholdBinary(new Gray(threshold), new Gray(255));pictureBox3.Image?.Dispose();pictureBox3.Image = binaryImage.ToBitmap();}/// <summary>/// 去噪音/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button4_Click(object sender, EventArgs e){Denoising();var bitmap6 = denoisingImage.ToBitmap();ShowTxt(bitmap6, label6);}private void Denoising(){if (binaryImage == null){MessageBox.Show("需要二值化图像");return;}int mksize = (int)numericUpDown6.Value;if ((mksize & 1) == 0){MessageBox.Show("MedianBlur的ksize必须为奇数");return;}denoisingImage?.Dispose();denoisingImage = new Image<Gray, byte>(binaryImage.Size);// 中值滤波//CvInvoke.MedianBlur(binaryImage, binaryImage, mksize);// 创建结构元素using Mat element = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size((int)numericUpDown1.Value, (int)numericUpDown2.Value), new Point(-1, -1));// 进行开运算CvInvoke.MorphologyEx(binaryImage, denoisingImage, MorphOp.Open, element, new Point(-1, -1), (int)numericUpDown5.Value, BorderType.Default, new MCvScalar());//CvInvoke.BitwiseNot(denoisingImage, denoisingImage);// 中值滤波CvInvoke.MedianBlur(denoisingImage, denoisingImage, mksize);ShowPictureBox(pictureBox4, denoisingImage);}/// <summary>/// 修复/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button7_Click(object sender, EventArgs e){RepairImage();var bitmap7 = repairImage.ToBitmap();ShowTxt(bitmap7, label7);}private void RepairImage(){if (denoisingImage == null){MessageBox.Show("请操作去噪音");return;}repairImage?.Dispose();// 创建结构元素using Mat element = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size((int)numericUpDown8.Value, (int)numericUpDown7.Value), new Point(-1, -1));repairImage = new Image<Gray, byte>(denoisingImage.Size);CvInvoke.MorphologyEx(denoisingImage, repairImage, MorphOp.Close, element, new Point(-1, -1), 1, BorderType.Default, new MCvScalar());ShowPictureBox(pictureBox6, repairImage);}// 创建卷积核float[,] kernelData = {{ -1, -1, -1 },{ -1, 9, -1 },{ -1, -1, -1 }
};// 定义锐化滤波器float[,] kernel = new float[,]{{ 0, -1, 0 },{ -1, 5, -1 },{ 0, -1, 0 }};/// <summary>/// 图像增强/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button5_Click(object sender, EventArgs e){ImageEnhancement();var bitmap = enhanceImage.ToBitmap();ShowTxt(bitmap, label4);}private void ImageEnhancement(){if (inputImage == null){MessageBox.Show("需要添加图片");return;}int gksize = (int)numericUpDown4.Value;if ((gksize & 1) == 0){MessageBox.Show("需要为奇数");return;}enhanceImage = new Image<Bgr, byte>(inputImage.Size);// 应用高斯模糊滤波器CvInvoke.GaussianBlur(inputImage, enhanceImage, new Size(gksize, gksize), 0);using Matrix<float> kernels = new Matrix<float>(kernel);// 应用卷积操作CvInvoke.Filter2D(enhanceImage, enhanceImage, kernels, new Point(-1, -1));// 创建锐化滤波器的内核//using Matrix<float> kernelMatrix = new Matrix<float>(kernelData);// 应用锐化滤波器//CvInvoke.Filter2D(enhanceImage, enhanceImage, kernelMatrix, new Point(-1, -1));// 将图像转换为 YCrCb 颜色空间Image<Ycc, byte> yccImage = enhanceImage.Convert<Ycc, byte>();// 将 YCrCb 图像的亮度通道应用自适应直方图均衡化CvInvoke.CLAHE(yccImage[0], 40.0, new Size(8, 8), yccImage[0]);enhanceImage.Dispose();// 将 YCrCb 图像转换回 Bgr 颜色空间enhanceImage = yccImage.Convert<Bgr, byte>();ShowPictureBox(pictureBox5, enhanceImage);}/// <summary>/// 文字识别/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void button6_Click(object sender, EventArgs e){//ExtractedText();}TesseractEngine engine = new TesseractEngine("D:\\个人\\tessdata-master", "eng", EngineMode.Default);private string ExtractedText(byte[] data){if (repairImage == null){MessageBox.Show("需要增强图像");return "";}// 加载图像using var image = Tesseract.Pix.LoadFromMemory(data);// 将图像传递给Tesseract引擎进行文字提取using var page = engine.Process(image);// 获取提取的文字string extractedText = page.GetText();//var mc = page.GetMeanConfidence();extractedText = FilterExtractedText(extractedText);return extractedText;}public byte[] BitmapToByteArray(Bitmap bitmap){using (MemoryStream stream = new MemoryStream()){bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);return stream.ToArray();}}public static Image<Bgr, byte> PerformTextCorrection(Image<Bgr, byte> inputImage){// 转换为灰度图像using Image<Gray, byte> grayImage = inputImage.Convert<Gray, byte>();// 进行边缘检测using Image<Gray, byte> edges = grayImage.Canny(50, 150);// 进行直线检测LineSegment2D[] lines = CvInvoke.HoughLinesP(edges, 1, Math.PI / 180, 100, 30, 10);// 计算所有直线的平均角度double averageAngle = lines.Average(line => Math.Atan2(line.P2.Y - line.P1.Y, line.P2.X - line.P1.X) * 180 / Math.PI);// 计算旋转中心PointF center = new PointF(inputImage.Width / 2f, inputImage.Height / 2f);// 创建旋转矩阵using Mat rotationMatrix = new Mat();CvInvoke.GetRotationMatrix2D(center, -averageAngle, 1.0, rotationMatrix);// 进行旋转using Image<Bgr, byte> rotatedImage = inputImage.WarpAffine(rotationMatrix, Inter.Linear, Warp.Default, BorderType.Constant, new Bgr(255, 255, 255));return rotatedImage;}private string FilterExtractedText(string extractedText){string txt = string.Empty;foreach (var item in extractedText){if (char.IsDigit(item))txt += item;else{int temp = (char)item;if (temp >= 65 && temp <= 90 || temp >= 97 && temp <= 122)txt += item;}}return txt;}}