其他分享
首页 > 其他分享> > 图片气泡统计

图片气泡统计

作者:互联网

最近这几天闲来无事,想起来18年12月末帮别人做了一个编程题。题目就是如何统计一张图片中的气泡数目,以及每个气泡的面积。

上面这张图就是案例,里面白色的都是不规则形态的气泡。当拿到这个题目时看一眼就大致有些思路。因为怎么说也是学了数据结构的人嘛!当时就是想借用数据结构中的“广度优先遍历”算法的思路去做。但是不全是,就是稍微改变一下。不过代码写完加调试估计花了我3个多小时,间接说明我编程能力赶不上我的思维能力。说白了我就菜......

        为了给别人理解,我当时就没有采用像素点(三维数据)去直接做,而是多做一步无用功。就是先把像素点降维成为一维数据并且进行简单的二分化。这里二分化就是把所有像素点变成纯黑或纯白,因为这张图片在黑白相间处的像素点存在杂色的像素点(毕竟不是矢量图)。

#coding:utf-8

from PIL import Image


# 打开图片,convert图像类型有L,RGBA
img = Image.open('1.jpg').convert('L')
img = img.transpose(Image.ROTATE_90)
#img.show();print(img.size[0],img.size[1])


# 将黑白图转化为0-1表示
def blackWrite(img):
    pixelShift = []
    for x in range(img.size[0]):
        rowList = []
        for y in range(img.size[1]):
            # 存在单一像素点不是纯黑纯白,取50为黑白分界线
            if img.getpixel((x,y)) < 50:
                rowList.append(0)
            else:
                rowList.append(1)
            pixelShift.append(rowList)
    return pixelShift

如果把一张图片看成一个二维数组,上面的代码就是把像素点变成0,1存储的二维数组,二维数组的行数和列数就是图片原始的分辨率大小。

然后你就可以把图片类型文件问题转变成我们基本都会的二维数组的字符问题了,剩下来就是如何对二维数组操作了。之前上面提到的“广度优先遍历”,学过数据结构的应该都知道这个图遍历算法。从一个点开始出发,查看它的四周有没有连接点(邻居),有的话就把它邻居都打入队列中去,然后没有邻居了之后就从队列的队首取出它之前的邻居点,然后查看这个点的邻居(就是邻居的邻居)。之后步骤和上面一样,但是需要对访问过的点做好标记,避免多次重复访问同一个点陷入死循环。

from queue import Queue


# 统计各气泡数字1
def statisticalNum(resultPixel):
    bubble = []     # 用于存放各气泡面积
    for x in range(len(resultPixel)):
        for y in range(len(resultPixel[0])):
            if resultPixel[x][y] == 1:
                resultPixel[x][y] = 0
                Coordinate = Queue()    # 存放该点四周为1的坐标点
                onlyCoordinate = []     # 防止重复的坐标点入队,并统计个数
                Coordinate.put([x,y])
                while not Coordinate.empty():
                    row = clo = 0
                    [row,clo] = Coordinate.get()
                    onlyCoordinate.append([row,clo])
                    # 查看左边坐标点
                    if clo > 0:
                        if (resultPixel[row][clo-1] == 1) and ([row,clo-1] not in onlyCoordinate):
                            Coordinate.put([row,clo-1])
                            resultPixel[row][clo-1] = 0
                    # 查看右边坐标点
                    if clo < (img.size[1]-1):
                        if (resultPixel[row][clo+1] == 1) and ([row,clo+1] not in onlyCoordinate):
                            Coordinate.put([row,clo+1])
                            resultPixel[row][clo+1] = 0
                    # 查看下边坐标点
                    if row < (img.size[0]-1):
                        if (resultPixel[row+1][clo] == 1) and ([row+1,clo] not in onlyCoordinate):
                            Coordinate.put([row+1,clo])
                            resultPixel[row+1][clo] = 0
                bubble.append(len(onlyCoordinate))
    return bubble

 

我的思路:

  1. 从第0行开始遍历,遇到第一个1(白色像素点)时,开始对其左,右,下三个方向数组点值做判断,周围邻居值是1就说明它们都在同一个气泡中,然后把邻居们压入队列中。

  2. 当这个点访问完成后,需要这个点的值1置为0表示访问完毕,避免它右邻居点在访问时把左边的它压入队列再次访问,会使得这个气泡的面积变大,甚至是死循环。(不要问我为什么这么清楚,呜呜呜呜呜)

  3. 把置0点的左边存在一个list列表中,类似c/java中的数组类型。

  4. 当第一层循环结束时得到了一个气泡,只需要用len方法就知道这个气泡点的个数,即面积。

  5. 然后第二次循环时,二维数组中的1减少一部分;即使代码是3个循环嵌套,也不要说我的代码时间复杂度是O(n^3)。

关于时间复杂度,我从来都喜欢用书本上的公式来衡量一个算法好坏。我就喜欢用实际中它运行的真实次数和时间来衡量一个算法的好坏。这么说吧,书上喜欢把O(n^2)+O(n)当成O(n^2)来衡量,忽略O(n)。如果在实际中n比较大的时候,O(n)消耗的资源成本也要考虑到的。想成为一个好的程序员就要比别人多注意一些细节,在大数据时代更是如此。

项目源码和图片的链接在此:https://gitee.com/mjTree/MyPython/tree/master/图片气泡统计

 

 

银长臂猿

        银长臂猿

标签:clo,img,resultPixel,气泡,图片,像素点,统计,row
来源: https://blog.csdn.net/m0_37713821/article/details/90575509