为何cv2.addWeighted中alpha值不更新,网格矩形透明度一致?
问题描述
我尝试在实时摄像头视频上叠加矩形网格,各矩形需根据normran数组的归一化值呈现不同透明度(本次测试未启用动态效果)。但所有矩形透明度均相同,代码循环执行正常,最终画面仅应用normran最后一个元素对应的alpha值。
原代码
#=========================================================================================================================== # Import Necessary Libraries import cv2 as cv import numpy as np from sklearn import preprocessing import math import itertools #=========================================================================================================================== # Define a Video Capture vid = cv.VideoCapture(0) #=========================================================================================================================== # Initialize height = int(input('Define Number of Rows: ')) width = int(input('Define Number of Columns: ')) hxw = height * width #=========================================================================================================================== # Create a Random Number Array randnums= np.random.randint(1,30000,(hxw)) normran = (randnums - randnums.min())/((randnums.max() - randnums.min())) print(normran) #=========================================================================================================================== # Create a Color Map def colorgrid(img, normran): h, w, _ = img.shape dy = h / height dx = w / width g = np.linspace(0, w-dx, width) b = np.linspace(g[1], w, width) t = np.linspace(0, h-dy, height) k = np.linspace(t[1], h, height) overlay = img.copy() thickness = 2 color3 = (0, 0, 0) color2 = (0, 0, 255) thickness1 = -1 i = -1 for spy, spay in itertools.product(t, k): for spx, spax in itertools.product(g, b): i = i + 1 alpha = normran[i] spx = int(round(spx)) spax = int(round(spax)) spy = int(round(spy)) spay = int(round(spay)) startx = (spx, spy) stopx = (spax, spay) print(alpha) print(i) cv.rectangle(overlay, startx, stopx, color2, thickness1) imgnew = cv.addWeighted(overlay, normran[i], img, 1, 0) cv.rectangle(img, startx, stopx, color3, thickness) if (i) == (hxw-1): i = -1 break return imgnew #=========================================================================================================================== # Use the Camera while(True): # the 'q' button is set as the # quitting button you may use any # desired button of your choice if cv.waitKey(1) & 0xFF == ord('q'): break # Capture the video frame # by frame ret, frame = vid.read() frame = cv.flip(frame,1) clr = colorgrid(frame, normran) # Display the resulting frame cv.imshow('Test', clr) # After the loop release the cap object vid.release() # Destroy all the windows cv.destroyAllWindows()
输入3行3列时的输出示例
0.90409176345848 0 0.07855800279531544 1 0.4564557328064003 2 0.9938310280013495 3 0.0 4 0.16005590630873778 5 1.0 6 0.9541182707600366 7 0.1760566774302376 8 0.90409176345848 0 0.07855800279531544 1 0.4564557328064003 2 0.9938310280013495 3 0.0 4 0.16005590630873778 5 1.0 6 0.9541182707600366 7 0.1760566774302376 8 ^^ this repeats infinitely
问题原因与修复方案
问题根源
原代码中每次循环都在同一个overlay图层上绘制矩形,然后调用cv.addWeighted将整个overlay与原图混合。这会导致后续矩形的绘制覆盖之前的透明度设置,最终只有最后一次混合操作的效果会保留在输出画面中。
修复后的代码
重点修改colorgrid函数,让每个矩形的透明度独立生效:
#=========================================================================================================================== # Import Necessary Libraries import cv2 as cv import numpy as np from sklearn import preprocessing import math import itertools #=========================================================================================================================== # Define a Video Capture vid = cv.VideoCapture(0) #=========================================================================================================================== # Initialize height = int(input('Define Number of Rows: ')) width = int(input('Define Number of Columns: ')) hxw = height * width #=========================================================================================================================== # Create a Random Number Array randnums= np.random.randint(1,30000,(hxw)) normran = (randnums - randnums.min())/((randnums.max() - randnums.min())) print(normran) #=========================================================================================================================== # Create a Color Map def colorgrid(img, normran): h, w, _ = img.shape dy = h / height dx = w / width # 生成所有网格的坐标,简化计算逻辑 grid_coords = [] for row in range(height): for col in range(width): x1 = int(col * dx) x2 = int((col + 1) * dx) y1 = int(row * dy) y2 = int((row + 1) * dy) grid_coords.append((x1, y1, x2, y2)) # 初始化结果图为原图副本 result = img.copy() thickness = 2 color3 = (0, 0, 0) color2 = (0, 0, 255) thickness1 = -1 # 遍历每个网格,独立计算透明度叠加 for i, (x1, y1, x2, y2) in enumerate(grid_coords): alpha = normran[i] # 创建临时图层,绘制当前矩形 temp_overlay = result.copy() cv.rectangle(temp_overlay, (x1, y1), (x2, y2), color2, thickness1) # 将当前矩形按alpha值混合到结果图 result = cv.addWeighted(temp_overlay, alpha, result, 1 - alpha, 0) # 绘制矩形边框 cv.rectangle(result, (x1, y1), (x2, y2), color3, thickness) return result #=========================================================================================================================== # Use the Camera while(True): if cv.waitKey(1) & 0xFF == ord('q'): break ret, frame = vid.read() frame = cv.flip(frame,1) clr = colorgrid(frame, normran) cv.imshow('Test', clr) vid.release() cv.destroyAllWindows()
修改说明
- 简化坐标计算:用行列循环直接生成每个网格的坐标,避免原代码中
itertools.product和linspace导致的坐标重复或计算冗余问题 - 独立叠加每个矩形:为每个矩形创建临时图层,混合后更新结果图,确保每个矩形的透明度设置不会被后续操作覆盖
- 优化循环逻辑:去掉原代码中多余的
i变量重置逻辑,用enumerate直接遍历网格坐标和normran数组
内容的提问来源于stack exchange,提问作者KissMyAfro
相关产品推荐
相关产品推荐

