Opencv的抠图的思路非常简单,就是对一个像素点进行判断,如果是需要剔除的像素,就把该像素的A通道改为0,即变为透明了。
今天就来实现下面这个效果把一个白色的透明通道,抠除的效果。
同样,要对图像操作,首先需要对图片进行读取,这是非常基本的了。而今天要获取图像上的一个像素点,那么就需要用到OpenCVForUnity这个插件中的获取像素点的方法。int[] get()
他是Mat容器上的实例方法他会返回一个Int数组,如果是JPG,这个数组的长度就是3,分别代表RGB值,如果是PNG,这个数组长度就是RGBA值。
首先我们获取图片的Mat,并把尺寸改小增加运行效率。
因为Logo是JPG,所以我们要把这个JPG装进一个四通道的容器里去。
而且我们知道图片中白色的RBA 是(255,255,255),而黑色的RBA是(0,0,0)
而我们只要判断这个像素点是不是等于255就能判断他是不是白色拉。而Mat.Put则是修改图片像素的方法,前面是图片的坐标点,后面跟着RGBA值,并保持原来的值,并把透明通道的值改为0;
但运行结果会发现锯齿很严重,抠不干净。
而我们也知道图片的像素其实是做了插值运算的,所以越是邻近黑色的像素点,并不等于255的。所以我们把他设置一个阈值。
你会发现比刚才干净很多。
但复杂抠图可比简单抠图要难很多,逻辑也要复杂很多,所以这里只是提供一个思路给大家,如何去改变一个像素值,获取一个像素值,你可以自己不断进行新的尝试。
下面是完整代码
void Start()
{
//把图片读进三通道的容器
var src = Imgcodecs.imread(Application.streamingAssetsPath + "/logo.jpg", 1);
// var mask = Imgcodecs.imread(Application.streamingAssetsPath+"/testsf.jpg",0);
//把尺寸设置为大小
Imgproc.resize(src, src, new Size(500, 500));
//建立一个四通道的容器
var dst = new Mat(src.cols(), src.rows(), CvType.CV_8UC4);
//转换色彩空间
Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGR2RGBA);
for (int i = 0; i < dst.cols(); i++)
{
for (int j = 0; j < dst.rows(); j++)
{
//这个105是阈值,你可以自己定义来试试效果
if (dst.get(j, i)[0] >105)
{
dst.put(j, i, 255, 255, 255, 0);
}
}
}
var tex = new Texture2D(dst.cols(), dst.rows(), TextureFormat.RGBA32, false);
Utils.matToTexture2D(dst, tex);
var raw = this.GetComponentInChildren();
raw.texture = tex;
raw.SetNativeSize();
}