【问题标题】:Extract the positions of their maximum pixel value of an image提取图像最大像素值的位置
【发布时间】:2019-12-08 17:29:55
【问题描述】:

我是这里的新手。我试图获得 2D 火焰边缘的单线,然后我可以计算实际面积 - 3D 火焰面积。第一件事是获得优势。二维火焰是一种侧视凹形火焰,因此火焰底部(平坦部分)比凹形部分更亮。我使用下面的代码来查找边缘,我的方法是查找沿 y 轴的最大像素值。结果似乎没有达到我的目的,你能帮我弄清楚吗?首先十分感谢。 Original image在代码中我旋转了图片

from PIL import Image
import numpy as np
import cv2

def initialization_rotate(path):
    global h,w,img
    img4 = np.array(Image.open(path).convert('L'))
    img3 = img4.transpose(1,0)
    img2 = img3[::-1,::1]
    img = img2[400:1000,1:248]
    h, w = img.shape

path = 'D:\\20190520\\14\\14\\1767.jpg'

#Noise cancellation
def opening(binary):
    opened = np.zeros_like(binary)              
    for j in range(1,w-1):
        for i in range(1,h-1):
            if binary[i][j]> 100:
                n1 = binary[i-1][j-1]
                n2 = binary[i-1][j]
                n3 = binary[i-1][j+1]
                n4 = binary[i][j-1]
                n5 = binary[i][j+1]
                n6 = binary[i+1][j-1]
                n7 = binary[i+1][j]
                n8 = binary[i+1][j+1]
                sum8 = int(n1) + int(n2) + int(n3) + int(n4) + int(n5) + int(n6) + int(n7) + int(n8)
                if sum8 < 1000:
                    opened[i][j] = 0
                else:
                    opened[i][j] = 255
            else:
                pass
    return opened    


edge = np.zeros_like(img)


# Find the max pixel value and extract the postion
for j in range(w-1):
    ys = [0]
    ymax = []
    for i in range(h-1):
         if img[i][j] > 100:
            ys.append(i)
        else:
            pass
    ymax = np.amax(ys)
    edge[ymax][j] = 255


cv2.namedWindow('edge')

while(True):
    cv2.imshow('edge',edge)
    k = cv2.waitKey(1) & 0xFF
    if k == 27:
        break


cv2.destroyAllWindows()

【问题讨论】:

  • 您想要获得二维阵列中最亮的单个像素,还是想要对背景噪声上方的点进行边缘检测?
  • 感谢您的评论。通过获取沿 y 轴在每列中具有最亮像素的所有点,我可以将它们全部收集起来以形成火焰的边缘。我的糟糕描述不好。
  • 你是在左边缘还是右边缘?
  • 能否提供一个 jpeg 文件的 url 让我进行边缘检测?最好是二维平面矩阵。
  • @YvesDaoust 感谢您的评论,这张照片是管中向下传播的火焰的瞬间。火焰在图像中从上到下传播,就像从右到左一样。

标签: python image-processing


【解决方案1】:

我已经完成了一个非常快速的编码,并且从头开始(没有研究关于边缘检测的已建立或最先进的算法)。不出所料,结果很差。我在下面粘贴的代码仅适用于 RGB(即仅适用于三个通道,不适用于 CMYK、灰度或 RGBA 或其他任何图像)。我还测试了一个非常简单的图像。在现实生活中,图像很复杂。我认为那里还不会很公平。它需要做很多工作。但是,由于@Gia Tri 的要求,我犹豫着分享它。

这就是我所做的。对于每一列,我计算了平均强度和标准差强度。我希望在边缘,强度会从平均 +- 标准差(乘以一个因子)发生变化。如果我标记列中的第一个和最后一个,我将为每一列都有边缘,并且一旦我缝合它,它就会形成和边缘。代码和附件图片供您查看,我的表现如何。

from scipy import ndimage
import numpy as np
import matplotlib.pyplot as plt

UppperStdBoundaryMultiplier = 1.0
LowerStdBoundaryMultiplier = 1.0
NegativeSelection = False

def SumSquareRGBintensityOfPixel(Pixel):
    return np.sum(np.power(Pixel,2),axis=0)

def GetTheContinousStretchForAcolumn(Column):
    global UppperStdBoundaryMultiplier
    global LowerStdBoundaryMultiplier
    global NegativeSelection
    SumSquaresIntensityOfColumn = np.apply_along_axis(SumSquareRGBintensityOfPixel,1,Column)
    Mean = np.mean(SumSquaresIntensityOfColumn)
    StdDev = np.std(SumSquaresIntensityOfColumn)
    LowerThreshold = Mean - LowerStdBoundaryMultiplier*StdDev
    UpperThreshold = Mean + UppperStdBoundaryMultiplier*StdDev
    if NegativeSelection:
        Index = np.where(SumSquaresIntensityOfColumn < LowerThreshold)
        Column[Index,:] = np.array([255,255,255])
    else:
        Index = np.where(SumSquaresIntensityOfColumn >= LowerThreshold)
        LeastIndex = Index[Index==True][0]
        LastIndex = Index[Index==True][-1]
        Column[[LeastIndex,LastIndex],:] =  np.array([255,0,0])
    return Column

def DoEdgeDetection(ImageFilePath):
    FileHandle = ndimage.imread(ImageFilePath)
    for Column in range(FileHandle.shape[1]):
        FileHandle[:,Column,:] = GetTheContinousStretchForAcolumn(FileHandle[:,Column,:])
    plt.imshow(FileHandle)
    plt.show()

DoEdgeDetection("/PathToImage/Image_1.jpg")

下面是结果。左侧是必须检测边缘的查询图像,右侧是边缘检测图像。边缘点用红点标记。正如你所看到的,它表现不佳,但投入了一些时间和思考,它可能会做得更好......或者可能不会。也许这是一个好的开始,但远未结束..请你做法官!

***** 澄清 GiaTri 的要求后编辑 ***************

所以我确实设法改变了程序,想法保持不变。但是,这一次问题被过度简化为您只想检测蓝色火焰的情况。实际上,我继续让它适用于所有三个颜色通道。但是我怀疑,它对您在蓝色通道之外有用。

**如何使用下面的程序**

如果你的火焰是垂直的,那么在班级分配中选择 edges = "horizo​​ntal"。如果您的边缘是水平的,则选择边缘 =“垂直”。这可能有点令人困惑,但暂时请使用它。以后要么你改,要么我改。

首先让我说服您,边缘检测的效果比昨天好得多。请参阅下面的两张图片。我从互联网上拍摄了这两个火焰图像。与之前一样,需要检测边缘的图像在左侧,右侧是边缘检测图像。边缘是红点。

第一个horizontal flame

然后是a vertical flame

.

这方面还有很多工作要做。但是,如果您比昨天更有信心,那么下面是代码。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.image import imread

class DetectEdges():

    def __init__(self, ImagePath, Channel = ["blue"], edges="vertical"):
        self.Channel = Channel
        self.edges = edges
        self.Image_ = imread(ImagePath)
        self.Image = np.copy(self.Image_)
        self.Dimensions_X, self.Dimensions_Y, self.Channels = self.Image.shape
        self.BackGroundSamplingPercentage = 0.5

    def ShowTheImage(self):
        plt.imshow(self.Image)
        plt.show()

    def GetTheBackGroundPixels(self):
        NumberOfPoints = int(self.BackGroundSamplingPercentage*min(self.Dimensions_X, self.Dimensions_Y))
        Random_X = np.random.choice(self.Dimensions_X, size=NumberOfPoints, replace=False)
        Random_Y = np.random.choice(self.Dimensions_Y, size=NumberOfPoints, replace=False)
        Random_Pixels = np.array(list(zip(Random_X,Random_Y)))
        return Random_Pixels

    def GetTheChannelEdge(self):
        BackGroundPixels = self.GetTheBackGroundPixels()
        if self.edges == "vertical":
            if self.Channel == ["blue"]:
                MeanBackGroundInensity = np.mean(self.Image[BackGroundPixels[:,0],BackGroundPixels[:,1],2])
                for column in range(self.Dimensions_Y):
                    PixelsAboveBackGround = np.where(self.Image[:,column,2]>MeanBackGroundInensity)
                    if PixelsAboveBackGround[PixelsAboveBackGround==True].shape[0] > 0:
                        TopPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][0]
                        BottomPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][-1]
                        self.Image[[TopPixel,BottomPixel],column,:] = [255,0,0]
            if self.Channel == ["red"]:
                MeanBackGroundInensity = np.mean(self.Image[BackGroundPixels[:,0],BackGroundPixels[:,1],0])
                for column in range(self.Dimensions_Y):
                    PixelsAboveBackGround = np.where(self.Image[:,column,0]>MeanBackGroundInensity)
                    if PixelsAboveBackGround[PixelsAboveBackGround==True].shape[0] > 0:
                        TopPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][0]
                        BottomPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][-1]
                        self.Image[[TopPixel,BottomPixel],column,:] = [0,255,0]
            if self.Channel == ["green"]:
                MeanBackGroundInensity = np.mean(self.Image[BackGroundPixels[:,0],BackGroundPixels[:,1],1])
                for column in range(self.Dimensions_Y):
                    PixelsAboveBackGround = np.where(self.Image[:,column,1]>MeanBackGroundInensity)
                    if PixelsAboveBackGround[PixelsAboveBackGround==True].shape[0] > 0:
                        TopPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][0]
                        BottomPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][-1]
                        self.Image[[TopPixel,BottomPixel],column,:] = [255,0,0]
        elif self.edges=="horizontal":
            if self.Channel == ["blue"]:
                MeanBackGroundInensity = np.mean(self.Image[BackGroundPixels[:,0],BackGroundPixels[:,1],2])
                for row in range(self.Dimensions_X):
                    PixelsAboveBackGround = np.where(self.Image[row,:,2]>MeanBackGroundInensity)
                    if PixelsAboveBackGround[PixelsAboveBackGround==True].shape[0] > 0:
                        LeftPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][0]
                        RightPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][-1]
                        self.Image[row,[LeftPixel,RightPixel],:] = [255,0,0]
            if self.Channel == ["red"]:
                MeanBackGroundInensity = np.mean(self.Image[BackGroundPixels[:,0],BackGroundPixels[:,1],0])
                for row in range(self.Dimensions_X):
                    PixelsAboveBackGround = np.where(self.Image[row,:,0]>MeanBackGroundInensity)
                    if PixelsAboveBackGround[PixelsAboveBackGround==True].shape[0] > 0:
                        LeftPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][0]
                        RightPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][-1]
                        self.Image[row,[LeftPixel,RightPixel],:] = [0,255,0]
            if self.Channel == ["green"]:
                MeanBackGroundInensity = np.mean(self.Image[BackGroundPixels[:,0],BackGroundPixels[:,1],1])
                for row in range(self.Dimensions_X):
                    PixelsAboveBackGround = np.where(self.Image[row,:,1]>MeanBackGroundInensity)
                    if PixelsAboveBackGround[PixelsAboveBackGround==True].shape[0] > 0:
                        LeftPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][0]
                        RightPixel = PixelsAboveBackGround[PixelsAboveBackGround==True][-1]
                        self.Image[row,[LeftPixel,RightPixel],:] = [255,0,0]



Test = DetectEdges("FlameImagePath",Channel = ["blue"],edges="vertical")
Test.GetTheChannelEdge()
Test.ShowTheImage()

请让我知道这是否有任何“更多”帮助或我错过了一些重要的要求。

祝你好运,

【讨论】:

  • 非常感谢,阿米特。它实际上在我的图像中并没有真正起作用,因为我的图像只是被认为是一种蓝色图像,而不是完全 RGB 图像。现在我对此没有任何评论,但我正在学习关于计算每列中平均强度的想法的代码。正如你所说,它需要更多的努力来完美匹配我的形象,我仍在努力。再次感谢。
  • 换一种方法来寻找每列像素的峰值强度,而不是使用平均强度如何?
  • 是的,可以做到。请等待几个小时。只要我靠近我的电脑,我就会尝试做出改变。谢谢。
  • 太棒了。因为使用平均强度,恐怕火焰的曲线部分(我是指细胞部分)不会被正确检测到,下面的部分,我是指强度较高的火焰底座(请参考链接:imgur.com/3bq4BuT) .所以有了峰值强度的想法,我认为代码可以消除曲线的下面部分(细胞形状)。
  • @GiaTri 情况比昨天有所改善。见上面的帖子。请告诉我。
【解决方案2】:

顺便说一下,Amit,我想使用阈值像素值的概念来展示我的代码。我很想和你讨论。

if __name__ == '__main__':
    path = 'D:\\20181229__\\7\\Area 7\\1767.jpg'
    img1 = cv2.imread(path)
    b,g,r = cv2.split(img1)
    img3 = b[94:223, 600:700]
    img4 = cv2.flip(img3, 1)
    h,w = img3.shape
    data = []
    th_val = 20
    for i in range(h):
        for j in range(w):
            val = img3[i, -j]
            if (val >= th_val):
                data.append(j)
                break

    x = range(len(data))
    plt.figure(figsize = (10, 7))
    plt.subplot(121)
    plt.imshow(img4)
    plt.plot(data, x)
    plt.subplot(121)
    plt.plot(data, x)

请查看结果链接。问题是方法仍然不完全符合我的愿望。我希望与您讨论。 链接:https://imgur.com/QtNk7c7

【讨论】:

  • 非常好。恭喜你解决了这个问题。我想知道做“img3 = b[94:223, 600:700]”的理由是什么?我的意思是索引中的数字来自哪里?
  • 其实就是图中火焰周围的刻度。该图像只是火焰在管中向下移动的传播中的一个帧,因此我需要限制代码执行其工作的范围以节省时间。我有大约 300 张图片。 94:223 接近火焰的垂直长度,如上面的链接所示。但是我想通过在每一行中找到峰值强度的想法来查看结果(按照链接中火焰的位置)。我认为我的代码可能不适合实际的火焰边缘。
  • 我明白你的逻辑,但这意味着你在编码之前对边缘有一个概念,而且你每次都必须改变。我还注意到您已将自己限制在蓝色频道。这是一个聪明的想法,但不是通用的。但是,如果您需要做的只是检测蓝色边缘,那么它很聪明。这也意味着问题更容易解决。请让我考虑一下。我会尝试发布更好的代码,或者可能会通过添加新代码来编辑我的帖子,但仅在几个小时后。
  • 其实图中的火焰是一种碳氢化合物的火焰,所以一般是蓝色的火焰。我知道这是贪婪,但如果没问题,您能否提供处理文件夹中所有图像的功能?非常感谢。
  • 我在这个问题上取得了一些进展。明天,我会努力把它弄得更多。暂时可以看到解决办法。
猜你喜欢
  • 2017-03-16
  • 1970-01-01
  • 2014-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-01
  • 2015-10-22
相关资源
最近更新 更多