0

这是图像中 Ascii 艺术生成器上的简单脚本,我收到此错误:我在 cmd 行中运行它,并且我使用的是 Windows 7 操作系统

Traceback (most recent call last):
File "C:\Python33\mbwiga.py", line 251, in <module>
converter.convertImage(sys.argv[-1])
File "C:\Python33\mbwiga.py", line 228, in convertImage
self.getBlobs()
File "C:\Python33\mbwiga.py", line 190, in getBlobs
width, height = self.cat.get_width(), self.cat.get_height()
AttributeError: 'NoneType' object has no attribute 'get_width'

我在这里搞砸什么..??有人可以帮忙吗..?

这是有人问的完整源代码:

import sys
import pygame

NAME = sys.argv[0]
VERSION = "0.1.0" # The current version number.

HELP = """ {0} : An ASCII art generator. Version {1}
Usage:
{0} [-b BLOB_SIZE] [-p FONT_WIDTH:HEIGHT] [-c] image_filename

Commands:
-b | --blob            Change the blob size used for grouping pixels. This is the width of the blob; the height is calculated by multiplying the blob size by the aspect ratio.
-p | --pixel-aspect    Change the font character aspect ratio. By default this is 11:5, which seems to look nice. Change it based on the size of your font. Argument is specified in the format "WIDTH:HEIGHT". The colon is important.
-c | --colour          Use colour codes in the output. {0} uses VT100 codes by default, limiting it to 8 colours, but this might be changed later.

-h | --help            Shows this help.""""


.format(NAME, VERSION)

NO_IMAGE = \
""" Usage: %s [-b BLOB_SIZE] [-p FONT_WIDTH:HEIGHT] image_filename """ % (NAME)

import math

CAN_HAS_PYGAME = False
try:
import pygame
except ImportError:
sys.stderr.write("Can't use Pygame's image handling! Unable to proceed, sorry D:\n")
exit(-1)

VT100_COLOURS = {"000": "[0;30;40m",
             "001": "[0;30;41m",
             "010": "[0;30;42m",
             "011": "[0;30;43m",
             "100": "[0;30;44m",
             "101": "[0;30;45m",
             "110": "[0;30;46m",
             "111": "[0;30;47m",
             "blank": "[0m"}

VT100_COLOURS_I = {"000": "[0;40;30m",
               "001": "[0;40;31m",
               "010": "[0;40;32m",
               "011": "[0;40;33m",
               "100": "[0;40;34m",
               "101": "[0;40;35m",
               "110": "[0;40;36m",
               "111": "[0;40;37m",
               "blank": "[0m"}

# Convenient debug function.
DO_DEBUG = True
def debug(*args):
if not DO_DEBUG: return # Abort early, (but not often).
strrep = ""
for ii in args:
    strrep += str(ii)
sys.stderr.write(strrep + "\n") # Write it to stderr. Niiicce.

# System init.
def init():
""" Start the necessary subsystems. """
pygame.init() # This is the only one at the moment...

# Get a section of the surface.
def getSubsurface(surf, x, y, w, h):
try:
    return surf.subsurface(pygame.Rect(x, y, w, h))
except ValueError as er:
    return getSubsurface(surf, x, y, w - 2, h - 2)

# The main class.
class AAGen:
""" A class to turn pictures into ASCII "art". """
def  __init__(self):
    """ Set things up for a default conversion. """

    # Various blob settings.
    self.aspectRatio = 11.0 / 5.0 # The default on my terminal.
    self.blobW = 12 # The width. Also, the baseline for aspect ratio.
    self.blobH = self.aspectRatio * self.blobW # The height.

    self.blobList = []
    self.cat = None # The currently open file.
    self.chars = """#@%H(ks+i,. """ # The characters to use.

    self.colour = False # Do we use colour?

def processArgs(self):
    """ Process the command line arguments, and remove any pertinent ones. """
    cc = 0
    for ii in sys.argv[1:]:
        cc += 1

        if ii == "-b" or ii == "--blob":
            self.setBlob(int(sys.argv[cc + 1]))

        elif ii == "-p" or ii == "--pixel-aspect":
            jj = sys.argv[cc + 1]
            self.setAspect(float(jj.split(":")[1]) / float(jj.split(":")[0]))
        elif ii == "-c" or ii == "--colour":
            self.colour = True

        elif ii == "-h" or ii == "--help":
            print(HELP)
            exit(0)

    if len(sys.argv) == 1:
        print(NO_IMAGE)
        exit(0)

def setBlob(self, blobW):
    """ Set the blob size. """
    self.blobW = blobW
    self.blobH = int(math.ceil(self.aspectRatio * self.blobW))

def setAspect(self, aspect):
    """ Set the aspect ratio. Also adjust the blob height. """
    self.aspectRatio = aspect
    self.blobH = int(math.ceil(self.blobW * self.aspectRatio))

def loadImg(self, fname):
    """ Loads an image into the store. """
    try:
        tmpSurf = pygame.image.load(fname)
    except:
        print("Either this is an unsupported format, or we had problems loading the file.")
        return None
    self.cat = tmpSurf.convert(32)

    if self.cat == None:
        sys.stderr.write("Problem loading the image %s. Can't convert it!\n"
                         % fname)
        return None

def makeBlob(self, section):
    """ Blob a section into a single ASCII character."""
    pxArr = pygame.surfarray.pixels3d(section)
    colour = [0, 0, 0]
    size = 0 # The number of pixels.

    # Get the density/colours.
    for i in pxArr:
        for j in i:
            size += 1
            # Add to the colour.
            colour[0] += j[0]
            colour[1] += j[1]
            colour[2] += j[2]

    # Get just the greyscale.
    grey = apply(lambda x, y, z: (x + y + z) / 3 / size,
                 colour)

    if self.colour:
        # Get the 3 bit colour.
        threshold = 128
        nearest = ""
        nearest += "1" if (colour[0] / size > threshold) else "0"
        nearest += "1" if (colour[1] / size > threshold) else "0"
        nearest += "1" if (colour[2] / size > threshold) else "0"

        return VT100_COLOURS[nearest], grey

    return grey

# We just use a nasty mean function to find the average value.
#        total = 0
#        for pix in pxArr.flat:
#            total += pix # flat is the array as a single-dimension one.

#        return total / pxArr.size # This is a bad way to do it, it loses huge amounts of precision with large blob size. However, with ASCII art...

  def getBlobs(self):
    """ Get a list of blob locations. """
    self.blobList = [] # Null it out.
    width, height = self.cat.get_width(), self.cat.get_height()

    # If the image is the wrong size for blobs, add extra space.
    if height % self.blobH != 0 or width % self.blobW != 0:
        oldimg = self.cat
        newW = width - (width % self.blobW) + self.blobW
        newH = height - (height % self.blobH) + self.blobH
        self.cat = pygame.Surface((newW, newH))

        self.cat.fill((255, 255, 255))
        self.cat.blit(oldimg, pygame.Rect(0, 0, newW, newH))

    # Loop over subsections.
    for row in range(0, height, int(self.blobH)):
        rowItem = []
        for column in range(0, width, self.blobW):
            # Construct a Rect to use.
            src = pygame.Rect(column, row, self.blobW, self.blobH)
            # Now, append the reference.
            rowItem.append(self.cat.subsurface(src))
        self.blobList.append(rowItem)

    return self.blobList

def getCharacter(self, value, colour = False):
    """ Get the correct character for a pixel value. """
    col = value[0] if colour else ""
    value = value[1] if colour else value
    if not 0 <= value <= 256:
        sys.stderr.write("Incorrect pixel data provided! (given %d)\n"
                         % value)
        return "E"
    char = self.chars[int(math.ceil(value / len(self.chars))) % len(self.chars)]
    return char + col

def convertImage(self, fname):
    """ Convert an image, and print it. """
    self.loadImg(fname)
    self.getBlobs()

    pval = "" # The output value.
    # Loop and add characters.
    for ii in converter.blobList:
        for jj in ii:
            ch = self.makeBlob(jj)
            pval += self.getCharacter(ch, self.colour) # Get the character.
        # Reset the colour at the end of the line.
        if self.colour: pval += VT100_COLOURS["blank"]

        pval += "\n" # Split it up by line.
    pval = pval[:-1] # Cut out the final newline.

    print(pval) # Print it.

# Main program execution.
if __name__ == "__main__":
init()

converter = AAGen()

converter.processArgs()
converter.convertImage(sys.argv[-1])

sys.exit(1)
4

1 回答 1

0

问题隐藏在loadImg. 错误说self.catNone. self.cat可能会在第None97 行初始化时获得 ,或者它被分配了结果tmpSurf.convert(32)并且该调用的结果是None. 在第一种情况下,您应该观察消息Either this is an unsupported format...,在后一种情况下,您应该在Problem loading the image...测试self.cat时看到消息None

def loadImg(self, fname):
    """ Loads an image into the store. """
    try:
        tmpSurf = pygame.image.load(fname)
    except:
        print("Either this is an unsupported format, or we had problems loading the file.")
        return None
    self.cat = tmpSurf.convert(32)

    if self.cat == None:
        sys.stderr.write("Problem loading the image %s. Can't convert it!\n"
                         % fname)
        return None

顺便说一句,与没有参数return None完全一样。return此外,最后一个return None可以完全删除,因为任何函数None在到达主体末尾时都会隐式返回。

对于测试Noneis建议使用操作员 - 即if self.cat is None:

根据 5 月 31 日的评论进行更新。

如果你想更进一步,你真的应该学一点 Python。看看原始脚本的结尾(缩进固定):

# Main program execution.
if __name__ == "__main__":
    init()                                # pygame is initialized here

    converter = AAGen()                   # you need the converter object

    converter.processArgs()               # the command-line arguments are
                                          # converted to the object attributes
    converter.convertImage(sys.argv[-1])  # here the conversion happens

    sys.exit(1)    # this is unneccessary for the conversion

如果原始脚本保存在 中mbwiga.py,则可以或将其作为脚本调用,也可以将其用作模块。后面的情况下,下面的bodyif __name__ == "__main__":没有被执行,需要自己在调用者脚本中执行。假设您有test.py尝试这样做。假设它位于同一目录中。它必须导入mbwiga. 然后mbwiga.成为模块内部功能的前缀。您的代码可能如下所示:

import mbwiga

mbwiga.init()                                # pygame is initialized here
converter = mbwiga.AAGen()                   # you need the converter object

# Now the converter is your own object name. It does not take the mbwiga. prefix.
# The original converter.processArgs() took the argumens from the command-line
# when mbwiga.py was called as a script. If you want to use some of the arguments
# you can set the converter object's attributes the way that is shown 
# in the .processArgs() method definition. Or you can call it the same way to
# extract the information from the command line passed when you called the test.py
#
converter.processArgs()

# Now the conversion    
converter.convertImage('myImageFilename.xxx')  # here the conversion happens
于 2013-05-28T09:47:15.960 回答