【问题标题】:put watermark on bottom left on multiple images in python opencv在python opencv中的多个图像的左下角放置水印
【发布时间】:2021-11-11 00:52:10
【问题描述】:

我是 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 必须改变

我有点困惑, 如何在多张图片的左下角添加水印?

【问题讨论】:

标签: python opencv image-processing opencv-python


【解决方案1】:

您的问题中的最后一个代码 sn-p 已经非常接近了。您的最终代码大部分都有效,您只需要概括水印所在的坐标。在图像中,左上角是坐标 (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 或不同的东西。这样做你计算出水印的坐标,但你检索到原始图像/水印尺寸。如果您这样做,您可能还想将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

它来自一个答案here。这将为您提供一个可以迭代的文件名列表,在您使用自己的代码读入后获取每个文件名的高度和宽度。

【讨论】:

  • 谢谢兄弟,关于调整水印大小我的意思是,有时图像太大而水印显示在缩略图中,或者有时图像太小而标志显示在大图像中跨度>
  • 所以我要根据每张图片的大小来调整水印的大小,希望你明白我的意思
  • @shahab-qazavi,我添加了一些调整大小的代码。用 opencv 调整水印的大小不是挑战,它知道你想要调整它的 dimensions。我提出了一种可能性,但还有其他可能性。您必须确保您的尺寸是整数,并且您的水印加上边框不超过图像大小(即,如果您希望水印覆盖整个图像,则需要边框为 0)。
  • 非常感谢,这正是我想要的
【解决方案2】:

这是我在 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;

给我以下结果:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-16
    • 2021-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多