图像切割无外乎用颜色(rgb,hsv等)形状(凹点,凸包,各种矩)区分,
纹理也很多,常用GLCM灰度共生矩阵,欺负人,又是opencv版本有,适合C#版本的没有,
即便有,也大多是基于标准矩形的,但实际应用的时候,我们往往要分析不规则图形。
本来想做个mask图像后,把灰度0-0(意思是某像素为0,该左侧的像素也为零,具体参考GLCM)剔除就行了,后来想想不对,万一图像内部也有0-0的像素,剔除了会造成干扰的。
水平不高,硬写了一段c#版本的非标GLCM,各位读者先凑合用吧,有心的帮我完善一下。
写成类了,如下:
256表示灰度级数,bp是灰度图,mask是灰度图的蒙版,a和b表示灰度值
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
namespace Count_Num
{
public class GLCM
{
public double[,] glmc;
double energy; // 能量
double entropy; // 熵
double contrast; // 对比度
double idMoment; // 逆差分矩, inverse difference moment
public double Energy { get => energy; set => energy = value; }
public double Entropy { get => entropy; set => entropy = value; }
public double Contrast { get => contrast; set => contrast = value; }
public double IdMoment { get => idMoment; set => idMoment = value; }
public GLCM(int size)
{
glmc = new double[size, size];
}
public unsafe double[,] calGLCM(Bitmap bp, Bitmap mask,int Size,int kind)
{
double[,] glmc = new double[Size, Size];
for (int i = 0; i < Size; i++)
{
for (int j = 0; j < Size; j++)
{
if (kind == 0)
glmc[i, j] = get_Oglmc(bp,mask,i,j);
if (kind == 90)
glmc[i, j] = get_9Oglmc(bp, mask, i, j);
if (kind == 45)
glmc[i, j] = get_45glmc(bp, mask, i, j);
if (kind == 135)
glmc[i, j] = get_135glmc(bp, mask, i, j);
}
}
return glmc;
}
public unsafe int get_Oglmc(Bitmap bp, Bitmap mask,int a,int b)
{
int sum = 0;
BitmapData dstData = bp.LockBits(new Rectangle(0, 0, bp.Width, bp.Height), ImageLockMode.ReadWrite, bp.PixelFormat);
BitmapData maskData = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadWrite, mask.PixelFormat);
byte* data = (byte*)(dstData.Scan0);
byte* maskdata = (byte*)(maskData.Scan0);
int step = dstData.Stride;
for (int i = 0; i < dstData.Height; i++)
{
for (int j = 0; j < dstData.Width - 1; j++)
{
if (maskdata[i * step + j] == 0 || maskdata[i * step + j+1] == 0)
if (data[i * step + j] == a && data[i * step + j+1] == b)
sum++;
}
}
bp.UnlockBits(dstData);
mask.UnlockBits(maskData);
return sum;
}
public unsafe int get_9Oglmc(Bitmap bp, Bitmap mask, int a, int b)
{
int sum = 0;
BitmapData dstData = bp.LockBits(new Rectangle(0, 0, bp.Width, bp.Height), ImageLockMode.ReadWrite, bp.PixelFormat);
BitmapData maskData = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadWrite, mask.PixelFormat);
byte* data = (byte*)(dstData.Scan0);
byte* maskdata = (byte*)(maskData.Scan0);
int step = dstData.Stride;
for (int i = 0; i < dstData.Height-1; i++)
{
for (int j = 0; j < dstData.Width; j++)
{
if (maskdata[i * step + j] == 0 || maskdata[(i+1) * step + j] == 0)
if (data[i * step + j] == a && data[(i+1) * step + j] == b)
sum++;
}
}
bp.UnlockBits(dstData);
mask.UnlockBits(maskData);
return sum;
}
public unsafe int get_45glmc(Bitmap bp, Bitmap mask, int a, int b)
{
int sum = 0;
BitmapData dstData = bp.LockBits(new Rectangle(0, 0, bp.Width, bp.Height), ImageLockMode.ReadWrite, bp.PixelFormat);
BitmapData maskData = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadWrite, mask.PixelFormat);
byte* data = (byte*)(dstData.Scan0);
byte* maskdata = (byte*)(maskData.Scan0);
int step = dstData.Stride;
for (int i = 0; i < dstData.Height-1; i++)
{
for (int j = 0; j < dstData.Width - 1; j++)
{
if (maskdata[i * step + j] == 0 || maskdata[(i+1) * step + j+1] == 0)
if (data[i * step + j] == a && data[(i+1) * step + j+1] == b)
sum++;
}
}
bp.UnlockBits(dstData);
mask.UnlockBits(maskData);
return sum;
}
public unsafe int get_135glmc(Bitmap bp, Bitmap mask, int a, int b)
{
int sum = 0;
BitmapData dstData = bp.LockBits(new Rectangle(0, 0, bp.Width, bp.Height), ImageLockMode.ReadWrite, bp.PixelFormat);
BitmapData maskData = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadWrite, mask.PixelFormat);
byte* data = (byte*)(dstData.Scan0);
byte* maskdata = (byte*)(maskData.Scan0);
int step = dstData.Stride;
for (int i = 0; i < dstData.Height-1; i++)
{
for (int j = 1; j < dstData.Width ; j++)
{
if (maskdata[i * step + j] == 0 || maskdata[(i+1) * step + j-1] == 0)
if (data[i * step + j] == a && data[(i+1) * step + j-1] == b)
sum++;
}
}
bp.UnlockBits(dstData);
mask.UnlockBits(maskData);
return sum;
}
public void getGLCMFeatures(double[,] glmc, int Size)
{
double total = 0;
for (int i = 0; i < Size; i++)
{
for (int j = 0; j < Size; j++)
{
total += glmc[i, j];
}
}
double[,] temp = new double[Size, Size];
// 归一化
for (int i = 0; i < Size; ++i)
{
for (int j = 0; j < Size; ++j)
{
temp[i,j] = glmc[i,j] / total;
}
}
for (int i = 0; i < Size; ++i)
{
for (int j = 0; j < Size; ++j)
{
energy += temp[i,j] * temp[i,j];
if (temp[i,j] > 0)
entropy -= temp[i,j] * Math.Log(temp[i,j]); //熵
contrast += (double)(i - j) * (double)(i - j) * temp[i,j]; //对比度
idMoment += temp[i,j] / (1 + (double)(i - j) * (double)(i - j));//逆差矩
}
}
}
}
}
调用:
GLCM glmc = new GLCM(256);
DataGridViewRow Temp_Row1 = new DataGridViewRow();
dataGridView1.Rows.Add(Temp_Row1);
glmc.glmc = glmc.calGLCM(mask0[i], mask0[i+1], 256, 0);
glmc.getGLCMFeatures(glmc.glmc, 256);
this.dataGridView1.Rows[i/2].Cells[0].Value = glmc.Energy;
this.dataGridView1.Rows[i/2].Cells[1].Value = glmc.Entropy;
this.dataGridView1.Rows[i/2].Cells[2].Value = glmc.Contrast;
this.dataGridView1.Rows[i/2].Cells[3].Value = glmc.IdMoment;
如下图,预处理切割出了四个字母和一个干扰项,干扰项的对比度和能量还是差异挺明显的。