Here is my overall instructions
Write a Color class that represents an RGB color using integer values in the range 0 to 255. Your class must:
Be placed in image.py
Provide a constructor that accepts the values of the red, green, and blue channels from the client and stores those values
Provide public methods that return the values of the red, green, and blue channels
Write a PortablePixmap class that represents a PPM image. Your class must:
Be placed in image.py
Provide a constructor that accepts the magic number, width, height, maximum color value, and pixel data from the client and stores those values
Store the pixel data as a list of (or list of lists of) Color objects
Provide a public method that returns a string representation of the PPM image
Write a read_ppm function that opens a PPM image file, reads its contents, and returns a PortablePixmap object that holds its contents. Your function must:
Be placed in image.py
Read the contents of a PPM image file
Not be sensitive to the formatting of the PPM image file
Exit with an error if the numbers of expected and provided pixels differ
Write a main function that tests your read_ppm function. Your function must be placed in main.py
this is what I have thus far
class Color:
# constructor takes in values from client and stores them
def __init__(self, red, green, blue):
# checks that type of arg == int: raises exception otherwise
if (isinstance(red, int) and isinstance(green, int) and isinstance(blue, int)):
print("good stuff, indeed integers")
else:
raise TypeError("Argument must be an integer.")
# checks if values are between 0 and 225
if red < 0 or red > 225:
print("0 < rgb values < 225")
elif green < 0 or green > 225:
print("0 < rgb values < 225")
elif blue < 0 or blue > 225:
print("0 < rgb values < 225")
# instance variables (RGB values)
self._red = red
self._green = green
self._blue = blue
# methods that reuturn RGB values
def returnRed(self):
return self._red
def returnGreen(self):
return self._green
def returnBlue(self):
return self._blue
'''class that represents a PPM image'''
class PortablePixmap:
def __init__(self, magic_number, width, height, max_color_value, pixel_data):
self._magic_number = magic_number
self._width = width
self._height = height
self._max_color_value = max_color_value
self._pixel_data = pixel_data
def __str__(self):
s = self._magic_number
s += '\n' + str(self._width)
s += ' ' + str(self._height)
s += '\n' + str(self._max_color_value)
for pixel in self._pixel_data:
s += ' ' + str(pixel[0])
s += ' ' + str(pixel[1])
s += ' ' + str(pixel[2])
return s
I have a few questions for clarification..
1. Did I go about creating the Color class correctly?
2. Do I even need to raise any exceptions in that class specifically? We will ultimately be reading from a file that contains everything in order but not necessarily on it's own individual line.
I really just want to know if I am going about this correctly. The instructions seem stepwise, but I am not really understanding how everything connects so I'm afraid I am either doing too much or too little.
Thanks in advance
It is not clear from the specification that you need to check the values, and your checks only raise exceptions in some cases, otherwise cause side effects (printing); from a reuse perspective, I'd prefer to have only the exceptions if any. Aside from the indentation error (which I assume is only here, not in your source) the Color class looks to cover the demands, although they are quite unpythonic with the accessors; probably someone was trained by Java.
The docstring should be inside the PortablePixmap class, not above it.
Most remarkable is the combination of demands that your class not be sensitive to the formatting of the PPM and store pixels as 8-bit unsigned RGB. This makes it impossible to support all PPMs, as they support 16-bit values (note the maxval field in the PPM format).
Your PortablePixmap class also doesn't use the Color class: "Store the pixel data as a list of (or list of lists of) Color objects". That requirement forces a rather awfully inefficient implementation, but the whole thing is an exercise, I suppose. You'll need to extract the RGB triplets from the pixel data string. That's also where you need the one check that is specified; verifying that there are exactly the right number of pixels. One would expect a ValueError exception if that fails.
If I were writing this sort of thing I might have used slots to reduce memory use for classes like Color, arrays to handle the large number of limited range numeric values, and possibly properties to make storage transparent without using unwieldy getter methods. split and join would make it easier to handle the collection of pixels.
Related
I was wondering if morphology.remove_small_objects could be used to remove big objects. I am using this tool to detect the objects as seen in the figure.
,
However,there are big objects as seen in the left. Is there any way I could use morphology.remove_small_objects as a threshold, for example:
mask=morphology.remove_small_objects(maske, 30)
Could I use like a range? between 30 and 200 so I can ignore the red detection in the image.
Otherwise, I will just count the white pixels in the image and remove the ones that have the highest.
This might be a good contribution to the scikit-image library itself, but for now, you need to roll your own. As suggested by Christoph, you can subtract the result of remove_small_objects from the original image to remove large objects. So, something like:
def filter_objects_by_size(label_image, min_size=0, max_size=None):
small_removed = remove_small_objects(label_image, min_size)
if max_size is not None:
mid_removed = remove_small_objects(small_removed, max_size)
large_removed = small_removed - mid_removed
return large_removed
else:
return small_removed
I am trying to find out the complementary color of a given color using Python. here is my code. the code returns error message telling "AttributeError: 'list' object has no attribute 'join'" I need a hint. In addition, there might be a more robust code which calculates the opposite/complementary color, which I am basically looking for. your suggestions will be helpful.
from PIL import Image
def complementaryColor(hex):
"""Returns complementary RGB color
Example:
>>>complementaryColor('FFFFFF')
'000000'
"""
if hex[0] == '#':
hex = hex[1:]
rgb = (hex[0:2], hex[2:4], hex[4:6])
comp = ['02%X' % (255 - int(a, 16)) for a in rgb]
return comp.join()
another similar function
def blackwhite(my_hex):
"""Returns complementary RGB color
Example:
>>>complementaryColor('FFFFFF')
'000000'
"""
if my_hex[0] == '#':
my_hex = my_hex[1:]
rgb = (my_hex[0:2], my_hex[2:4], my_hex[4:6])
comp = ['%X' % (0 if (15 - int(a, 16)) <= 7 else 15) for a in rgb]
return ''.join(comp)
print blackwhite('#36190D')
Your join and formatting needed a fix. Lists do not have a join method, strings do:
def complementaryColor(my_hex):
"""Returns complementary RGB color
Example:
>>>complementaryColor('FFFFFF')
'000000'
"""
if my_hex[0] == '#':
my_hex = my_hex[1:]
rgb = (my_hex[0:2], my_hex[2:4], my_hex[4:6])
comp = ['%02X' % (255 - int(a, 16)) for a in rgb]
return ''.join(comp)
The formatting for hex shoud be %02X for two hex characters and not '02%X'. The later only appends a leading 02 to a mangled output of 3 characters instead of 6.
hex is builtin function, so you may consider changing the name to, say my_hex to avoid shadowing the original hex function.
You can use colorir's palettes for that:
>>> from colorir import SwatchPalette
>>> colors = SwatchPalette.new_complementary(2, color="ff0000")
>>> colors[1] # Get the complementary of red
HexRGB(#00ffff)
Of course you can pass any color you want to new_complementary's "color" parameter to get its complementary color.
I am working with the CMLN-13S2C-CS CCD camera from PointGrey Systems. It uses FlyCapture API to grab images. I would like to grab these images and do some stuff in OpenCV with them using python.
I am aware of the following python binding: pyflycapture2. With this binding I am able to retrieve images. However, I cannot retrieve the images in color, which is what the camera should be able to do.
The videomode and framerate that the camera is able to handle are VIDEOMODE_1280x960Y8, and FRAMERATE_15, respectively. I think it has something to do with the pixel_format, which I think should be raw8.
Is anyone able to retrieve a color image using this or any existing python binding for flycapture? Note that I am working on Linux.
You don't need to use the predefined modes. The Context class has the set_format7_configuration(mode, x_offset, y_offset, width, height, pixel_format) method with which you can use your custom settings. Using this you can at least change the resolution of the grabbed image.
Usage example:
c.set_format7_configuration(fc2.MODE_0, 320, 240, 1280, 720, fc2.PIXEL_FORMAT_MONO8)
As for the coloring issue. I've so far managed to get a colored image using PIXEL_FORMAT_RGB8 and modifying the Image class in flycapture2.pyx as follows:
def __array__(self):
cdef np.ndarray r
cdef np.npy_intp shape[3] # From 2 to 3
cdef np.dtype dtype
numberofdimensions = 2 # New variable
if self.img.format == PIXEL_FORMAT_MONO8:
dtype = np.dtype("uint8")
elif self.img.format == PIXEL_FORMAT_MONO16:
dtype = np.dtype("uint16")
elif self.img.format == PIXEL_FORMAT_RGB8: # New condition
dtype = np.dtype("uint8")
numberofdimensions = 3
shape[2] = 3
else:
dtype = np.dtype("uint8")
Py_INCREF(dtype)
shape[0] = self.img.rows
shape[1] = self.img.cols
# nd value (numberofdimensions) was always 2; stride set to NULL
r = PyArray_NewFromDescr(np.ndarray, dtype,
numberofdimensions, shape, NULL,
self.img.pData, np.NPY_DEFAULT, None)
r.base = <PyObject *>self
Py_INCREF(self)
return r
This code is most likely not flawless (i.e I removed the stride stuff) for the simple reason that I have pretty much 0 experience with C and Cython but this way I at least managed to get a colored frame (now in the process of trying to get the PIXEL_FORMAT_RAW8 working).
And just as a reminder: the flycapture2.pyx is a Cython file so you need to recompile it before you can use it (I just run the pyflycap2 install script again).
I'm using the same camera with Matlab and also got an issues with "raw8" format. So, I've chose "rgb8", specifically, "F7_RGB_644x482_Mode1" and all things starts to work (not sure, how it should look at Python).
P.S. At the moment I'm trying to start work with Python and pyflycapture2, let's see, if I would be able to find workaround.
UPD: Okay, now I know the things. :)
Your (and mine) issue reasons are buried inside the pyflycapture2 itself, especially "Image" class definition. You can have a look here: https://github.com/jordens/pyflycapture2/blob/eec14acd761e89d8e63a0961174e7f5900180d54/src/flycapture2.pyx
if self.img.format == PIXEL_FORMAT_MONO8:
dtype = np.dtype("uint8")
stride[1] = 1
elif self.img.format == PIXEL_FORMAT_MONO16:
dtype = np.dtype("uint16")
stride[1] = 2
else:
dtype = np.dtype("uint8")
stride[1] = self.img.stride/self.img.cols
ANY image will be converted into grayscale, even if it was RGB initially. So, we need to update that file somehow.
The following code is the initialization method of a basic Angle object with float as its parent class.
class Angle(float):
def __init__(self, value, vertex2 = None, vertex3 = None, atype = 'convex'):
#type-checking for the input args
try:
#checks for value arg
angle = value
if not (0 < value < 360):
angle %= 360
except TypeError:
#checks for three-vertice args
try:
angle = three_point_angle(value, vertex2, vertex3)
#three_point_angle is a function to calculate the
#convex angle between three vertices (i.e. at vertex2)
if atype == 'concave':
angle = 360 - angle
self._vdict = {}
for pos, vert in enumerate([value, vertex2, vertex3]):
self._vdict[pos] = vert
except:
raise TypeError(\
"You may only specify either an angle value, or three vertices from which \
to calculate the angle. You input a %s, %s and %s value." % (\
type(value), type(vertex2), type(vertex3)))
self.angle = angle
The idea behind this class is that you can either input a value for the angle, or specify three vertices (and an optional angle type parameter) to automatically calculate the angle. In the end, self.angle is always initialized, and this is where all the arithmetic takes place (so __add__(self, other) would affect self.angle).
The reason it inherits from float is to inherit its magic methods for reflective and augmented assignment, which are all performed on self.angle.
The problem arises when one tries to input three values for the vertices. Since it inherits from float, it can't take more than one argument, and as such raises an error. How would I work around this? My guess is that I would have to create a __new__ method for Angle, such that it would be invoked instead of the superclass', but I have no clue where I'd even start with that or even if it's the right/best way to go about this.
You don't need to inherit from float. You're incorrect in thinking that magic methods are performed on self.angle; they're just performed on self. Try the following code:
class Angle(float):
def __init__(self, x):
self.angle = x
def double(self):
self.angle *= 2
a = Angle(1)
a.double()
print a # prints 1.0
print a.angle # prints 2
a *= 5
print a # prints 5.0
print a.angle # throws AttributeError
a.angle isn't affected by magic methods, nor is float(a) affected by operations on a.angle. floats are immutable, so a *= 5 created a new float, with different attributes.
So, if you change Angle to inherit from Object instead of float, you can control initialization, without losing any convenience.
See this related question:
How to overload `float()` for a custom class in Python?
then change
class Angle(float):
to
class Angle(object):
I'm using PIL
im = Image.open(teh_file)
if im:
colors = im.resize( (1,1), Image.ANTIALIAS).getpixel((0,0)) # simple way to get average color
red = colors[0] # and so on, some operations on color data
The problem is, on a few (very few, particulary don't know why those exactly, simple jpegs) I get 'unsubscriptable object' on line "colors[0]". Tried:
if colors:
gets true and goes on.
if len(colors):
gives 'len() of unsized object'
What condition should I apply not to get this exception?
What's the cause of the problem?
From the PIL docs:
getpixel
im.getpixel(xy) => value or tuple
Returns the pixel at the given position. If the image is a multi-layer image, this method returns a tuple.
So it seems that some of your images are multilayer, and some are single-layer.
As noted in another answer, getpixel returns either a single value, or a tuple. You could check the type and do the appropriate action in the following ways:
if isinstance(colors, tuple):
color = colors[0]
else:
color = colors
# Do other stuff
or:
try:
color = colors[0]
except: # Whatever the exception is - IndexError or whatever
color = colors
# Do other stuff
The second way is probably more Pythonic.
Ok the case was, that when B&W images have no RGB band (L band), it returns an integer with the pixel color single value, not a list of rgb values. The solution is to check bands
im.getbands()
or the simpler for my needs was:
if isinstance(colors, tuple):
values = {'r':colors[0], 'g':colors[1], 'b':colors[2]}
else:
values = {'r':colors, 'g':colors, 'b':colors}