python-3.x 如何取出使用OpenCV拍摄的screnshot的平均颜色?

vulvrdjw  于 2022-11-19  发布在  Python
关注(0)|答案(3)|浏览(105)

我正在尝试开发一个设备,根据我的显示器的颜色来改变RGB灯带。为此,我计划对屏幕进行截图,并对显示器中各个像素的颜色进行归一化/取平均值。我在对图像进行归一化和取平均值时遇到了麻烦。下面是我使用的代码。

import numpy as np
import cv2
import mss
import time  

def getAverageColor(frame):
    (B, G, R) = 0, 0, 0
    for i in frame:
        for j in i:
            B += j[0]
            G += j[1]
            R += j[2]
    B /= len(frame) * len(frame[0])
    G /= len(frame) * len(frame[0])
    R /= len(frame) * len(frame[0])
    return (B, G, R)


with mss.mss() as sct:
    # Grab frames in an endless lopp until q key is pressed
        time.sleep(2)
        # Itterate the list of monitors, and grab one frame from each monitor (ignore index 0)
        for monitor_number, mon in enumerate(sct.monitors[1:]):
            monitor = {"top": mon["top"], "left": mon["left"], "width": mon["width"], "height": mon["height"], "mon": monitor_number}  # Not used in the example

            # Grab the data
            img = np.array(sct.grab(mon)) # BGRA Image (the format BGRA, at leat in Wiqndows 10).
            print(getAverageColor(img))
            # Show down-scaled image for testing
            # The window name is img0, img1... applying different monitors.
            cv2.imshow(f'img{monitor_number}', cv2.resize(img, (img.shape[1]//4, img.shape[0]//4)))
            key = cv2.waitKey(1)
            if key == ord('q'):
                break

cv2.destroyAllWindows()

程序运行良好,但我想问一下,是否有任何方法可以去掉openCV本身的平均颜色,因为我的方法不是很好,因为它在处理过程中非常缓慢。不是要添加这个,但代码也不是很准确。

sc4hvdpw

sc4hvdpw1#

在Python中,使用列表和for循环进行图像处理效率低、速度慢且容易出错。请尝试使用Numpy或矢量化库,如OpenCVscikit-imagewandPIL/Pillow
制作一个从石灰绿色到黄色的渐变图像样本,即没有蓝色,纯绿色和红色渐变,这将给我们提供简单、易于检查的方法:

magick -size 256x256 gradient:lime-yellow png24:start.png

现在使用Numpy获取所有三个通道的平均值:

import cv2
import numpy as np

# Load image
im = cv2.imread('start.png')

print(im.shape)       # prints (256, 256, 3)

meanBlue  = np.mean(im[...,0])     # gets value=0
meanGreen = np.mean(im[...,1])     # gets value=255.0
meanRed   = np.mean(im[...,2])     # gets value=127.5
nnt7mjpx

nnt7mjpx2#

我更新了函数getAverageColor,目的是找到主色。我相信这会提供更好的颜色选择。时间是个问题,我会更新的,以防我能找到一种方法让它更快。

import pandas as pd
from scipy.cluster.vq import whiten
from scipy.cluster.vq import kmeans
# import matplotlib.pyplot as plt

def getAverageColor(frame):
  r = []
  g = []
  b = []
  print("Frames")
  for row in frame:
      for temp_r, temp_g, temp_b, temp in row:
          r.append(temp_r)
          g.append(temp_g)
          b.append(temp_b)
  
  df = pd.DataFrame({'r' : r, 'g' : g, 'b' : b})
    
  df['scaled_r'] = whiten(df['r'])
  df['scaled_b'] = whiten(df['b'])
  df['scaled_g'] = whiten(df['g'])
    
  cluster_centers, _ = kmeans(df[['scaled_r', 'scaled_b', 'scaled_g']], 3)
    
  dominant_colors = []
    
  r_std, g_std, b_std = df[['r', 'g', 'b']].std()
    
  for cluster_center in cluster_centers:
      red_scaled, green_scaled, blue_scaled = cluster_center
      dominant_colors.append((red_scaled * r_std / 255, green_scaled * g_std / 255, blue_scaled * b_std / 255))
  
  print("Dominant", dominant_colors)
  return(dominant_colors[0])
  # plt.imshow([dominant_colors])
  # plt.show()
xxhby3vn

xxhby3vn3#

我想用一个简单的解决方案来回答这个问题。这可能不是这个问题的最佳解决方案,但它对我的用例来说足够快了。如果有人能改进我的解决方案,我将不胜感激。

def getAverageColor(frame):
        r = []
        g = []
        b = []
        print("Frames")
        for row in frame:
            for pixel in row:
                r.append(pixel[0])
                g.append(pixel[1])
                b.append(pixel[2])

        r_mean = np.mean(r)
        g_mean = np.mean(g)
        b_mean = np.mean(b)
    
        return(r_mean, g_mean, b_mean)

这取出了所有像素的平均值,并且不像之前定义的解决方案那样,仅返回平均颜色,在90%的情况下,该平均颜色仅是棕色的阴影。

相关问题