首页 > 解决方案 > 非零值的 opencv meanStdDev

问题描述

我想计算忽略零的图像的平均值和统计数据。由于我没有弄清楚如何在 cv2.meanStdDev 中为此使用 mask 参数,我认为我可以通过一些数学来解决问题。

根据https://github.com/opencv/opencv/blob/master/3rdparty/carotene/src/meanstddev.cpp

标准偏差根据https://en.wikipedia.org/wiki/Standard_deviation计算为:

f64 stddev = sqrt(std::max(fsqsum * itotal - mean * mean, 0.0));

下面的代码现在尝试“重新使用该公式”来修复为所有不应考虑的零添加的值的结果

import cv2
import numpy as np
import math

def test_Stats():    
    h=2
    w=2
    channels=3

    image=np.zeros((h,w,channels), np.uint8)
    image[0,0]=(100,50,200)
    image[0,1]=(120,60,220)
    (means, stds) = cv2.meanStdDev(image)
    gmean,bmean,rmean=means.flatten()
    gstds,bstds,rstds=stds.flatten()
    print ("means %.1f %.1f %.1f " % (gmean,bmean,rmean))
    print ("stds  %.1f %.1f %.1f " % (gstds,bstds,rstds))
    b = image[:,:,0]
    g = image[:,:,1]
    r = image[:,:,2]
    h, w = image.shape[:2]
    pixels=h*w
    nonzerotupel= cv2.countNonZero(b),cv2.countNonZero(g),cv2.countNonZero(r)
    nonzero=max(nonzerotupel)
    print ("%d pixel %d non-zero" % (pixels,nonzero))
    factor=pixels/nonzero
    fgmean=gmean*factor
    fbmean=bmean*factor
    frmean=rmean*factor
    print ("non-zero means %.1f %.1f %.1f" % (fgmean,fbmean,frmean))
    fsqsumb=(bstds*bstds+bmean*bmean)/pixels
    fsqsumg=(gstds*gstds+gmean*gmean)/pixels
    fsqsumr=(rstds*rstds+rmean*rmean)/pixels
    fstdsb=math.sqrt(max(fsqsumb*nonzero-fbmean*fbmean,0))
    fstdsg=math.sqrt(max(fsqsumg*nonzero-fgmean*fgmean,0))
    fstdsr=math.sqrt(max(fsqsumr*nonzero-frmean*frmean,0))
    print ("non-zero stds %.1f %.1f %.1f" % (fstdsb,fstdsg,fstdsr))

运行它:

test_Stats() 

给出:

means 55.0 27.5 105.0 
stds  55.5 27.7 105.2 
4 pixel 2 non-zero
non-zero means 110.0 55.0 210.0
non-zero stds 0.0 0.0 0.0

所以看起来我犯了一些错误。在此示例中,非零标准的预期结果将是 10.0,5.0,10.0

解决办法是什么?

修复后如何进一步改进此代码?

标签: pythonopencvmath

解决方案


我想我发现了错误。第一个问题的答案:解决办法是什么?在下面。

原因:c++ 版本中的 itotal 意思是“逆总数” - 1/total。我以为它的意思是“整数总数”。因此需要修复像素非零调整。结果是现在

means 55.00 27.50 105.00 
stds  55.45 27.73 105.24 
4 pixel 2 non-zero
non-zero means 110.00 55.00 210.00
fsqsum 6100.00 24400.00 88400.00
non-zero stds 5.00 10.00 10.00

看起来不错 问题 2:修复后如何进一步改进此代码? 仍然开放

def test_Stats():    
    h=2
    w=2
    channels=3

    image=np.zeros((h,w,channels), np.uint8)
    image[0,0]=(100,50,200)
    image[0,1]=(120,60,220)
    (means, stds) = cv2.meanStdDev(image)
    gmean,bmean,rmean=means.flatten()
    gstds,bstds,rstds=stds.flatten()
    print ("means %.2f %.2f %.2f " % (gmean,bmean,rmean))
    print ("stds  %.2f %.2f %.2f " % (gstds,bstds,rstds))
    b = image[:,:,0]
    g = image[:,:,1]
    r = image[:,:,2]
    h, w = image.shape[:2]
    pixels=h*w
    nonzerotupel= cv2.countNonZero(b),cv2.countNonZero(g),cv2.countNonZero(r)
    nonzero=max(nonzerotupel)
    print ("%d pixel %d non-zero" % (pixels,nonzero))
    factor=pixels/nonzero
    fgmean=gmean*factor
    fbmean=bmean*factor
    frmean=rmean*factor
    print ("non-zero means %.2f %.2f %.2f" % (fgmean,fbmean,frmean))
    fsqsumb=(bstds*bstds+bmean*bmean)*pixels
    fsqsumg=(gstds*gstds+gmean*gmean)*pixels
    fsqsumr=(rstds*rstds+rmean*rmean)*pixels
    print ("fsqsum %.2f %.2f %.2f" % (fsqsumb,fsqsumg,fsqsumr))
    fstdsb=math.sqrt(max(fsqsumb/nonzero-fbmean*fbmean,0))
    fstdsg=math.sqrt(max(fsqsumg/nonzero-fgmean*fgmean,0))
    fstdsr=math.sqrt(max(fsqsumr/nonzero-frmean*frmean,0))
    print ("non-zero stds %.2f %.2f %.2f" % (fstdsb,fstdsg,fstdsr))

作为一个函数:

def fixMeans(self,means,stds,pixels,nonzero):
        """ fix the zero based means to nonzero based see https://stackoverflow.com/a/58891531/1497139"""
        gmean,bmean,rmean=means.flatten()
        gstds,bstds,rstds=stds.flatten()
        if Color.debug:
            print ("means %.2f %.2f %.2f " % (gmean,bmean,rmean))
            print ("stds  %.2f %.2f %.2f " % (gstds,bstds,rstds))
        factor=pixels/nonzero
        fgmean=gmean*factor
        fbmean=bmean*factor
        frmean=rmean*factor
        if Color.debug:
            print ("non-zero means %.2f %.2f %.2f" % (fgmean,fbmean,frmean))
        fsqsumb=(bstds*bstds+bmean*bmean)*pixels
        fsqsumg=(gstds*gstds+gmean*gmean)*pixels
        fsqsumr=(rstds*rstds+rmean*rmean)*pixels
        if (Color.debug):
            print ("fsqsum %.2f %.2f %.2f" % (fsqsumb,fsqsumg,fsqsumr))
        fstdsb=math.sqrt(max(fsqsumb/nonzero-fbmean*fbmean,0))
        fstdsg=math.sqrt(max(fsqsumg/nonzero-fgmean*fgmean,0))
        fstdsr=math.sqrt(max(fsqsumr/nonzero-frmean*frmean,0))   
        if Color.debug:
            print ("non-zero stds %.2f %.2f %.2f" % (fstdsb,fstdsg,fstdsr))
        fixedmeans=fgmean,fbmean,frmean
        fixedstds=fstdsb,fstdsg,fstdsr
        return fixedmeans,fixedstds 

推荐阅读