基于opencv的图片加水印实现方案

加水印应该是个很常见的需求,但是网上找的代码,都感觉不太完善。记录下自己搞出来的一个方案

水印有几个需求:

  1. 中文文字水印
  2. 文字倾斜
  3. 满图都是,而不是只有一个地方
  4. 水印文字所在之处完全展示水印

实现思路

准备水印图

我是这么做的,先手工生成一张水印图,尺寸比较小,约100*100。然后也把文字旋转一定角度(当然如果想做随机角度,也是可以的,代码再复杂点处理就好,不影响这个思路),生成这个一张图片,并且底色选择纯黑

然后用opencv将水印图处理出一张二值图

这个也不难,底色纯黑,这个很好做,用Threshold很容易实现。

然后用水印图和原图叠加

核心就是要用copyTo(),然后要输入mask,二值图的作用就是做掩码,这样就可以实现完美的水印添加效果。

其他细节

因为水印图通常是远小于原图的(其实也可以采用其他方案。总之核心就是要有水印图和对应的二值图),如何实现满图添加水印呢?

思路

  1. 先设置一个水印的间距,比如两百个像素点
  2. 然后通过水印图的大小和间距的值,计算生成一个尺寸大于等于原图的纯水印图(同时也要有二值图)
  3. 然后裁剪成和原图一样大
  4. 然后用copyTo()叠加即可。

这样性能很高,go语言实现处理一张图片不超过10ms。

go语言实现

思路都是通用的,基于opencv都能实现。

go 复制代码
func ImgWatermark(img gocv.Mat) {
	var Watermark gocv.Mat
	var WatermarkBW gocv.Mat
	// 不同通道的图片使用不同的水印
	if img.Channels() == 3 {
		// 判断是否需要初始化
		if g.Watermark3 == nil { // g. 是我设置的全局变量,因为不需要每次都加载水印。加载一次到内存即可
			mat := gocv.IMRead(`watermark.jpg`, gocv.IMReadColor)
			g.Watermark3 = &mat

			// 取得水印图片的二值图
			watermarkGray3 := gocv.NewMat()
			gocv.CvtColor(*g.Watermark3, &watermarkGray3, gocv.ColorBGRToGray)
			// 取得二值图的黑白图
			BW3 := gocv.NewMat()
			g.WatermarkBW3 = &BW3
			gocv.Threshold(watermarkGray3, g.WatermarkBW3, 30, 255, gocv.ThresholdBinary)
			watermarkGray3.Close()
		}
		Watermark = *g.Watermark3
		WatermarkBW = *g.WatermarkBW3
	} else if img.Channels() == 4 {
		// 判断是否需要初始化
		if g.Watermark4 == nil {
			mat := gocv.IMRead(`watermark.jpg`, gocv.IMReadColor)
			g.Watermark4 = &mat
			gocv.Merge([]gocv.Mat{mat, gocv.NewMatWithSizeFromScalar(gocv.NewScalar(255, 255, 255, 255), mat.Rows(), mat.Cols(), gocv.MatTypeCV8UC1)}, g.Watermark4)
			// 取得水印图片的二值图
			watermarkGray4 := gocv.NewMat()
			gocv.CvtColor(*g.Watermark4, &watermarkGray4, gocv.ColorBGRToGray)
			// 取得二值图的黑白图
			BW4 := gocv.NewMat()
			g.WatermarkBW4 = &BW4
			gocv.Threshold(watermarkGray4, g.WatermarkBW4, 30, 255, gocv.ThresholdBinary)
			watermarkGray4.Close()
		}
		Watermark = *g.Watermark4
		WatermarkBW = *g.WatermarkBW4
	} else if img.Channels() == 1 {
		// 判断是否需要初始化
		if g.Watermark1 == nil {
			mat := gocv.IMRead(`watermark.jpg`, gocv.IMReadGrayScale) // 直接读取黑白
			g.Watermark1 = &mat
			// 取得二值图的黑白图
			BW1 := gocv.NewMat()
			g.WatermarkBW1 = &BW1
			gocv.Threshold(mat, g.WatermarkBW1, 30, 255, gocv.ThresholdBinary)
		}
		Watermark = *g.Watermark1
		WatermarkBW = *g.WatermarkBW1
	} else {
		fmt.Println("图片通道数不支持", img.Channels())
		return
	}
	waterCol := Watermark.Cols()
	waterRow := Watermark.Rows()
	// 为了水印不要那么密,这里设置一个间距
	spacing := 200 // 水印的间距

	waterColAndSpacing := waterCol + spacing
	watreRowAndSpacing := waterRow + spacing

	// 计算需要添加水印的次数
	watermarkHugeRowTimes := int(math.Ceil(float64(img.Rows()) / float64(watreRowAndSpacing))) //向上取整
	watermarkHugeColTimes := int(math.Ceil(float64(img.Cols()) / float64(waterColAndSpacing)))

	imgRect := image.Rectangle{} //每次取图像中哪一块区域的数据结构
	var croppedMat gocv.Mat      // 每次从原图像上裁剪和水印图像一样大小的一块

	newWater := Watermark
	newWaterBW := WatermarkBW
	// 循环一块块的给图像添加水印
	for i := 0; i < watermarkHugeColTimes; i++ {
		imgRect.Min.X = i * waterColAndSpacing
		imgRect.Max.X = imgRect.Min.X + waterCol
		if imgRect.Max.X >= img.Cols() { // 判断是否超出原图像的列数
			imgRect.Max.X = img.Cols()
		}
		for j := 0; j < watermarkHugeRowTimes; j++ {
			imgRect.Min.Y = j * watreRowAndSpacing
			imgRect.Max.Y = imgRect.Min.Y + waterRow
			if imgRect.Max.Y >= img.Rows() { // 判断是否超出原图像的行数
				imgRect.Max.Y = img.Rows()
			}
			croppedMat = img.Region(imgRect) // 原图像中一块区域的浅拷贝,修改它会连带修改原图像

			// 判断裁剪的图像大小是否与水印图像大小一致,不一致则需要重新裁剪
			if croppedMat.Rows() != Watermark.Rows() || croppedMat.Cols() != Watermark.Cols() {
				newRect := image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: croppedMat.Cols(), Y: croppedMat.Rows()}}
				newWater = Watermark.Region(newRect)
				newWaterBW = WatermarkBW.Region(newRect)
			}

			newWater.CopyToWithMask(&croppedMat, newWaterBW) // 用水印图覆盖原图像
		}
	}
}
相关推荐
uncle_ll5 分钟前
PyTorch图像预处理:计算均值和方差以实现标准化
图像处理·人工智能·pytorch·均值算法·标准化
只怕自己不够好42 分钟前
OpenCV 图像运算全解析:加法、位运算(与、异或)在图像处理中的奇妙应用
图像处理·人工智能·opencv
华清远见IT开放实验室2 小时前
【每天学点AI】实战图像增强技术在人工智能图像处理中的应用
图像处理·人工智能·python·opencv·计算机视觉
只怕自己不够好3 小时前
《OpenCV 图像缩放、翻转与变换全攻略:从基础操作到高级应用实战》
人工智能·opencv·计算机视觉
安静读书8 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
小陈phd8 小时前
OpenCV从入门到精通实战(九)——基于dlib的疲劳监测 ear计算
人工智能·opencv·计算机视觉
如若12313 小时前
主要用于图像的颜色提取、替换以及区域修改
人工智能·opencv·计算机视觉
哈市雪花16 小时前
图像处理 之 凸包和最小外围轮廓生成
图像处理·人工智能·图形学·最小外围轮廓·最小外包
如若12316 小时前
实现了图像处理、绘制三维坐标系以及图像合成的操作
图像处理·人工智能
lsjweiyi16 小时前
极简AI工具箱网站开源啦!
opencv·开源·微信支付·支付宝支付·百度ai·极简ai工具箱·ai图像处理