在 python opencv 中的多个图像的左下角放置水印
put watermark on bottom left on multiple images in python opencv
我是 OpenCV 新手,
我会很乐意帮助我
我有一张这样的透明水印图片
我想用 python OpenCV
在多张图片的左下角添加水印
每张图片大小不一
在放置之前我想调整水印的大小以适应图像的大小,徽标不应按比例缩小或放大
类似于这张图片:
这是我的代码:
import cv2
img1 = cv2.imread('my_image.png')
img2 = cv2.imread('my_watermark.png')
h, w = img1.shape[:2]
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols]
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 220, 255, cv2.THRESH_BINARY_INV)
mask_inv = cv2.bitwise_not(mask)
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
img2_fg = cv2.bitwise_and(img2,img2,mask = mask)
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0: cols] = dst
cv2.imwrite('imglogo.png', img1)
但是这段代码有两个问题
首先,水印位于图片的右上角
其次,水印失去透明度
图像变成这样
我试试这个:
image = cv2.imread('my_image.png')
watermark = cv2.imread('my_watermark.png', cv2.IMREAD_UNCHANGED)
(wH, wW) = watermark.shape[:2]
weight = 1 - watermark[:, :, 3] / 255
num1 = 1250
num2 = 50
image[num1:num1 + wH, num2:num2 + wW, 0] = np.multiply(image[num1:num1 + wH, num2:num2 + wW, 0], weight).astype(np.uint8)
image[num1:num1 + wH, num2:num2 + wW, 1] = np.multiply(image[num1:num1 + wH, num2:num2 + wW, 1], weight).astype(np.uint8)
image[num1:num1 + wH, num2:num2 + wW, 2] = np.multiply(image[num1:num1 + wH, num2:num2 + wW, 2], weight).astype(np.uint8)
output = cv2.addWeighted(image[num1:num1 + wH, num2:num2 + wW], 1, watermark[:, :, 0:3], 1, 1)
image[num1:num1 + wH, num2:num2 + wW] = output
cv2.imwrite("watermark3.png", image)
但在不同的图片中,每张图片的大小都会发生变化
所以,必须更改 num1 和 num2
我有点困惑,
如何在多张图片的左下角添加水印?
这是我在 C++ 中已有的解决方案,我相信您可以将其转换为 python:
cv::Mat mat = cv::imread("gimp.png", cv::ImreadModes::IMREAD_UNCHANGED);
cv::Mat mat1 = cv::imread("orange.jpg");
cv::Rect cvRectangle;
cvRectangle.x = 0;
cvRectangle.y = 0;
cvRectangle.width = mat.cols;
cvRectangle.height = mat.rows;
if (mat.empty() || mat1.empty())
return 1;
switch (mat.channels())
{
case 4:
{
cv::Mat src = mat1(cvRectangle).clone();
for (int y = 0; y < src.rows; y++)
{
const cv::Vec3b* src_pixel = src.ptr<cv::Vec3b>(y);
const cv::Vec4b* ovl_pixel = mat.ptr<cv::Vec4b>(y);
cv::Vec3b* dst_pixel = mat1(cvRectangle).ptr<cv::Vec3b>(y);
for (int x = 0; x < src.cols; x++, ++src_pixel, ++ovl_pixel, ++dst_pixel)
{
double alpha = (*ovl_pixel).val[3] / 255.0;
for (int c = 0; c < 3; c++)
{
(*dst_pixel).val[c] = (uchar)((*ovl_pixel).val[c] * alpha + (*src_pixel).val[c] * (1.0 - alpha));
}
}
}
}
break;
case 3:
{
cv::Mat src = mat1(cvRectangle).clone();
cv::addWeighted(src, 0, mat, 1, 0.0, mat1(cvRectangle));
}
break;
}
cv::imshow("image", mat1);
cv::waitKey(0);
return 0;
给我以下结果:
您的问题中的最后一个代码片段就快完成了。您的最终代码大部分都有效,您只需要概括水印所在的坐标。在图像中,左上角是坐标 (0,0)。所以如果你添加下面的代码,你可以计算出一个合适的坐标将水印放在图片的左下角:
(wH, wW) = watermark.shape[:2]
(iH, iW) = image.shape[:2]
border = 50 # allowing a 50 pixel border between the edge of the image and the start of the watermark.
num1 = iH - (wH + border)
num2 = border
此代码允许图像边缘和水印开始之间有一个固定的 50 像素边界。您可能希望使用 // 将其设置为图像尺寸的一部分,并且您可能希望使用不同的水平和垂直图像偏移量。请注意,此代码目前假定您的所有图像至少比水印大 50 像素(水平和垂直)。
如果您希望它位于图片的右下角,您只需:
num1 = iH - (wH + border)
num2 = iW - (wW + border)
您还提到调整图像大小。我建议你做的是弄清楚你想要水印占据图像的比例,所以假设你想要它至少是图像宽度的十分之一(1/10)但您想保持水印的像素纵横比:
# Resize the watermark
nwW = int(iW // 10)
nwH = int((nwW/wW) * wH)
resized = cv2.resize(watermark, (nwW, nwH), interpolation = cv2.INTER_AREA)
watermark = resized
wW = nwW
wH = nwH
那\10
就是“十分之一”的设定。也许您会想要“三分之一”\3
或其他内容。在之前你计算出水印去向的坐标但是在之后你已经检索到原始的image/watermark尺寸.如果您这样做,您可能还想将 border
设置为图像尺寸的比例(而不是平坦的 50 像素边框)。
您还询问了如何在多个图像上进行处理。为此,您可以使用此功能创建一个文件列表(无论您的图像格式实际是什么,请交换 .jpg):
import os
#Useful function
def createFileList(myDir, format='.jpg'):
fileList = []
print(myDir)
for root, dirs, files in os.walk(myDir, topdown=False):
for name in files:
if name.endswith(format):
fullName = os.path.join(root, name)
fileList.append(fullName)
return fileList
来自回答。这将为您提供一个文件名列表,您可以遍历这些文件名,并在您使用自己的代码读入后获取每个文件的高度和宽度。
我是 OpenCV 新手, 我会很乐意帮助我
我有一张这样的透明水印图片
我想用 python OpenCV
在多张图片的左下角添加水印每张图片大小不一
在放置之前我想调整水印的大小以适应图像的大小,徽标不应按比例缩小或放大
类似于这张图片:
这是我的代码:
import cv2
img1 = cv2.imread('my_image.png')
img2 = cv2.imread('my_watermark.png')
h, w = img1.shape[:2]
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols]
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 220, 255, cv2.THRESH_BINARY_INV)
mask_inv = cv2.bitwise_not(mask)
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
img2_fg = cv2.bitwise_and(img2,img2,mask = mask)
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0: cols] = dst
cv2.imwrite('imglogo.png', img1)
但是这段代码有两个问题
首先,水印位于图片的右上角
其次,水印失去透明度
图像变成这样
我试试这个:
image = cv2.imread('my_image.png')
watermark = cv2.imread('my_watermark.png', cv2.IMREAD_UNCHANGED)
(wH, wW) = watermark.shape[:2]
weight = 1 - watermark[:, :, 3] / 255
num1 = 1250
num2 = 50
image[num1:num1 + wH, num2:num2 + wW, 0] = np.multiply(image[num1:num1 + wH, num2:num2 + wW, 0], weight).astype(np.uint8)
image[num1:num1 + wH, num2:num2 + wW, 1] = np.multiply(image[num1:num1 + wH, num2:num2 + wW, 1], weight).astype(np.uint8)
image[num1:num1 + wH, num2:num2 + wW, 2] = np.multiply(image[num1:num1 + wH, num2:num2 + wW, 2], weight).astype(np.uint8)
output = cv2.addWeighted(image[num1:num1 + wH, num2:num2 + wW], 1, watermark[:, :, 0:3], 1, 1)
image[num1:num1 + wH, num2:num2 + wW] = output
cv2.imwrite("watermark3.png", image)
但在不同的图片中,每张图片的大小都会发生变化
所以,必须更改 num1 和 num2
我有点困惑, 如何在多张图片的左下角添加水印?
这是我在 C++ 中已有的解决方案,我相信您可以将其转换为 python:
cv::Mat mat = cv::imread("gimp.png", cv::ImreadModes::IMREAD_UNCHANGED);
cv::Mat mat1 = cv::imread("orange.jpg");
cv::Rect cvRectangle;
cvRectangle.x = 0;
cvRectangle.y = 0;
cvRectangle.width = mat.cols;
cvRectangle.height = mat.rows;
if (mat.empty() || mat1.empty())
return 1;
switch (mat.channels())
{
case 4:
{
cv::Mat src = mat1(cvRectangle).clone();
for (int y = 0; y < src.rows; y++)
{
const cv::Vec3b* src_pixel = src.ptr<cv::Vec3b>(y);
const cv::Vec4b* ovl_pixel = mat.ptr<cv::Vec4b>(y);
cv::Vec3b* dst_pixel = mat1(cvRectangle).ptr<cv::Vec3b>(y);
for (int x = 0; x < src.cols; x++, ++src_pixel, ++ovl_pixel, ++dst_pixel)
{
double alpha = (*ovl_pixel).val[3] / 255.0;
for (int c = 0; c < 3; c++)
{
(*dst_pixel).val[c] = (uchar)((*ovl_pixel).val[c] * alpha + (*src_pixel).val[c] * (1.0 - alpha));
}
}
}
}
break;
case 3:
{
cv::Mat src = mat1(cvRectangle).clone();
cv::addWeighted(src, 0, mat, 1, 0.0, mat1(cvRectangle));
}
break;
}
cv::imshow("image", mat1);
cv::waitKey(0);
return 0;
给我以下结果:
您的问题中的最后一个代码片段就快完成了。您的最终代码大部分都有效,您只需要概括水印所在的坐标。在图像中,左上角是坐标 (0,0)。所以如果你添加下面的代码,你可以计算出一个合适的坐标将水印放在图片的左下角:
(wH, wW) = watermark.shape[:2]
(iH, iW) = image.shape[:2]
border = 50 # allowing a 50 pixel border between the edge of the image and the start of the watermark.
num1 = iH - (wH + border)
num2 = border
此代码允许图像边缘和水印开始之间有一个固定的 50 像素边界。您可能希望使用 // 将其设置为图像尺寸的一部分,并且您可能希望使用不同的水平和垂直图像偏移量。请注意,此代码目前假定您的所有图像至少比水印大 50 像素(水平和垂直)。
如果您希望它位于图片的右下角,您只需:
num1 = iH - (wH + border)
num2 = iW - (wW + border)
您还提到调整图像大小。我建议你做的是弄清楚你想要水印占据图像的比例,所以假设你想要它至少是图像宽度的十分之一(1/10)但您想保持水印的像素纵横比:
# Resize the watermark
nwW = int(iW // 10)
nwH = int((nwW/wW) * wH)
resized = cv2.resize(watermark, (nwW, nwH), interpolation = cv2.INTER_AREA)
watermark = resized
wW = nwW
wH = nwH
那\10
就是“十分之一”的设定。也许您会想要“三分之一”\3
或其他内容。在之前你计算出水印去向的坐标但是在之后你已经检索到原始的image/watermark尺寸.如果您这样做,您可能还想将 border
设置为图像尺寸的比例(而不是平坦的 50 像素边框)。
您还询问了如何在多个图像上进行处理。为此,您可以使用此功能创建一个文件列表(无论您的图像格式实际是什么,请交换 .jpg):
import os
#Useful function
def createFileList(myDir, format='.jpg'):
fileList = []
print(myDir)
for root, dirs, files in os.walk(myDir, topdown=False):
for name in files:
if name.endswith(format):
fullName = os.path.join(root, name)
fileList.append(fullName)
return fileList
来自回答