随着csdn博客系统升级,尝试使用md写文章,感觉还不错。继续使用OpenCVForUnity处理图片,今次的效果是灰度化和二值化,当所有功能实现后,可能会做出一个unity版的美图秀秀。
首先我们来确定一下两者的概念。
- 二值化,就是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。
- 灰度化,在RGB模型中,如果R=G=B时,则彩色表示一种灰度颜色,其中R=G=B的值叫灰度值,因此,灰度图像每个像素只需一个字节存放灰度值(又称强度值、亮度值),灰度范围为0-255。
什么,没看懂?那看一下这张图吧,解释了什么叫做“有一张好图,就可以什么也不用解释了”。
构建一个简单的场景
很明显,灰度图的取值范围比二值图大,那么我们就先生成灰度图,再通过将灰度值设置为0或255生成二值图。
- 创建一个空场景,使用ugui摆好一个RawImage(或Image),和两个按钮。
- 创建一个Binaryzation类。Awake()中注册RawImage的约束比例,和2个按钮的点击方法,这里我先把二值化按钮交互关闭,灰度化处理后再激活。
[SerializeField] private RawImage targetImage;
[SerializeField] private Button grayButton;
[SerializeField] private Button binaryButton;
private AspectRatioFitter aspectRatioFitter;
void Awake()
{
aspectRatioFitter = targetImage.GetComponent<AspectRatioFitter>();
grayButton.onClick.AddListener(OnGray);
binaryButton.interactable = false;
binaryButton.onClick.AddListener(OnBinary);
}
- Start()中读取一张本地图片,并在RawImage上显示这张图片。注意这里使用Imgcodecs.imread()这个API从本地读取图片,需要在读取后做一些列通道转换。
private Mat srcMat, dstMat;
void Start()
{
srcMat = Imgcodecs.imread(Application.dataPath + "/Textures/kizuna.jpg", 1);
List<Mat> channels = new List<Mat>();
Core.split(srcMat, channels);
Mat imageRed = new Mat();
imageRed = channels[0];
Mat imageGreen = new Mat();
imageGreen = channels[1];
Mat imageBlue = new Mat();
imageBlue = channels[2];
channels[0] = channels[2];
channels[2] = imageRed;
Mat mergeImage = new Mat();
Core.merge(channels, srcMat);
aspectRatioFitter.aspectRatio = (float)srcMat.width() / (float)srcMat.height();
Texture2D t2d = new Texture2D(srcMat.width(), srcMat.height());
Utils.matToTexture2D(srcMat, t2d);
targetImage.texture = t2d;
}
- 使用Imgproc.cvtColor()方法将之前读取的Mat转为灰度。代码里也举例了一种简便的方法,在读取时直接转灰度,可省略转换步骤。然后把Mat转Texture2D,再显示到RawImage上,完成图像灰度化的效果。
void OnGray()
{
binaryButton.interactable = true;
//方法1.读取时就转为灰度
//srcMat = Imgcodecs.imread(Application.dataPath + "/Textures/kizuna.jpg", 0); //flag=0,将读入的彩色图像直接以灰度图像读入
//方法2.将现有Mat转为灰度
Imgproc.cvtColor(srcMat, srcMat, Imgproc.COLOR_BGR2GRAY); // 转为灰度图像
Texture2D t2d = new Texture2D(srcMat.width(), srcMat.height());
Utils.matToTexture2D(srcMat, t2d);
targetImage.texture = t2d;
}
- 将灰度的Mat克隆一个副本,使用Imgproc.threshold()进行二值化处理,通过阈值(minThresh, maxThresh)调节取值范围。
private double minThresh = 200d; //0(黑)->255(白)
private double maxThresh = 250d;
void OnBinary()
{
//克隆一个副本
dstMat = srcMat.clone();
//二值化处理
Imgproc.threshold(srcMat, dstMat, minThresh, maxThresh, Imgproc.THRESH_BINARY_INV); //CV_THRESH_BINARY
Texture2D t2d = new Texture2D(dstMat.width(), dstMat.height());
Utils.matToTexture2D(dstMat, t2d);
targetImage.texture = t2d;
}