From 2e98d8c21c71fa7d2d5a4bd8fded4ac8f0cbd906 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Thu, 20 Jun 2013 19:06:14 -0400 Subject: [PATCH 01/51] Added novice submodule after rebase --- CONTRIBUTORS.txt | 3 + skimage/data/block.png | Bin 0 -> 186 bytes skimage/data/elephant.png | Bin 0 -> 128401 bytes skimage/novice/__init__.py | 69 +++ skimage/novice/colors.csv | 865 ++++++++++++++++++++++++++++ skimage/novice/colors.py | 865 ++++++++++++++++++++++++++++ skimage/novice/make_colors.py | 60 ++ skimage/novice/novice.py | 778 +++++++++++++++++++++++++ skimage/novice/tests/test_novice.py | 123 ++++ 9 files changed, 2763 insertions(+) create mode 100644 skimage/data/block.png create mode 100644 skimage/data/elephant.png create mode 100644 skimage/novice/__init__.py create mode 100644 skimage/novice/colors.csv create mode 100644 skimage/novice/colors.py create mode 100644 skimage/novice/make_colors.py create mode 100644 skimage/novice/novice.py create mode 100644 skimage/novice/tests/test_novice.py diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index f8f78c52..39a2f988 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -158,3 +158,6 @@ - Fedor Morozov Drawing: Wu's anti-aliased circle + +- Michael Hansen + novice submodule diff --git a/skimage/data/block.png b/skimage/data/block.png new file mode 100644 index 0000000000000000000000000000000000000000..cd981597e24a22bf394d9785f676d2f9ebd906fb GIT binary patch literal 186 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 from skimage import novice # special submodule for beginners + + >>> picture = novice.open('sample.png') # create a picture object from a file + >>> print picture.format # pictures know their format... + 'png' + >>> print picture.path # ...and where they came from... + '/Users/example/sample.png' + >>> print picture.size # ...and their size + (665, 500) + >>> print picture.width # 'width' and 'height' also exposed + 665 + >>> picture.size = (200, 250) # changing size automatically resizes + >>> for pixel in picture: # can iterate over pixels + >>> ... if ((pixel.red > 128) and # pixels have RGB (values are 0-255)... + >>> ... (pixel.x < picture.width)): # ...and know where they are + >>> ... pixel.red /= 2 # pixel is an alias into the picture + >>> ... + >>> print picture.modified # pictures know if their pixels are dirty + True + >>> print picture.path # picture no longer corresponds to file + None + >>> picture[0:20, 0:20] = (0, 0, 0) # overwrite lower-left rectangle with black + >>> picture.save('sample-bluegreen.jpg') # guess file type from suffix + >>> print picture.path # picture now corresponds to file + '/Users/example/sample-bluegreen.jpg' + >>> print picture.format # ...has a different format + jpeg + >>> print picture.modified # and is now in sync + False +""" + +import os as _os +from .colors import * +from .novice import Picture + +def open(path): + """ + Creates a new Picture object from the given image path + """ + return Picture(path=_os.path.abspath(path)) + +def new(size, color=None): + """ + Create a new RGB picture of the given size, initialized to the + given color or to black if none is provided. + """ + return Picture(size=size, color=color) + +def copy(image): + """ + Creates a Picture using the supplied image data + (e.g., skimage.data.elephant()). + """ + return Picture(image=image) diff --git a/skimage/novice/colors.csv b/skimage/novice/colors.csv new file mode 100644 index 00000000..05e78540 --- /dev/null +++ b/skimage/novice/colors.csv @@ -0,0 +1,865 @@ +air_force_blue_raf,"Air Force Blue (Raf)",#5d8aa8,93,138,168 +air_force_blue_usaf,"Air Force Blue (Usaf)",#00308f,0,48,143 +air_superiority_blue,"Air Superiority Blue",#72a0c1,114,160,193 +alabama_crimson,"Alabama Crimson",#a32638,163,38,56 +alice_blue,"Alice Blue",#f0f8ff,240,248,255 +alizarin_crimson,"Alizarin Crimson",#e32636,227,38,54 +alloy_orange,"Alloy Orange",#c46210,196,98,16 +almond,Almond,#efdecd,239,222,205 +amaranth,Amaranth,#e52b50,229,43,80 +amber,Amber,#ffbf00,255,191,0 +amber_sae_ece,"Amber (Sae/Ece)",#ff7e00,255,126,0 +american_rose,"American Rose",#ff033e,255,3,62 +amethyst,Amethyst,#96c,153,102,204 +android_green,"Android Green",#a4c639,164,198,57 +anti_flash_white,"Anti-Flash White",#f2f3f4,242,243,244 +antique_brass,"Antique Brass",#cd9575,205,149,117 +antique_fuchsia,"Antique Fuchsia",#915c83,145,92,131 +antique_ruby,"Antique Ruby",#841b2d,132,27,45 +antique_white,"Antique White",#faebd7,250,235,215 +ao_english,"Ao (English)",#008000,0,128,0 +apple_green,"Apple Green",#8db600,141,182,0 +apricot,Apricot,#fbceb1,251,206,177 +aqua,Aqua,#0ff,0,255,255 +aquamarine,Aquamarine,#7fffd4,127,255,212 +army_green,"Army Green",#4b5320,75,83,32 +arsenic,Arsenic,#3b444b,59,68,75 +arylide_yellow,"Arylide Yellow",#e9d66b,233,214,107 +ash_grey,"Ash Grey",#b2beb5,178,190,181 +asparagus,Asparagus,#87a96b,135,169,107 +atomic_tangerine,"Atomic Tangerine",#f96,255,153,102 +auburn,Auburn,#a52a2a,165,42,42 +aureolin,Aureolin,#fdee00,253,238,0 +aurometalsaurus,Aurometalsaurus,#6e7f80,110,127,128 +avocado,Avocado,#568203,86,130,3 +azure,Azure,#007fff,0,127,255 +azure_mist_web,"Azure Mist/Web",#f0ffff,240,255,255 +baby_blue,"Baby Blue",#89cff0,137,207,240 +baby_blue_eyes,"Baby Blue Eyes",#a1caf1,161,202,241 +baby_pink,"Baby Pink",#f4c2c2,244,194,194 +ball_blue,"Ball Blue",#21abcd,33,171,205 +banana_mania,"Banana Mania",#fae7b5,250,231,181 +banana_yellow,"Banana Yellow",#ffe135,255,225,53 +barn_red,"Barn Red",#7c0a02,124,10,2 +battleship_grey,"Battleship Grey",#848482,132,132,130 +bazaar,Bazaar,#98777b,152,119,123 +beau_blue,"Beau Blue",#bcd4e6,188,212,230 +beaver,Beaver,#9f8170,159,129,112 +beige,Beige,#f5f5dc,245,245,220 +big_dip_o_ruby,"Big Dip O’Ruby",#9c2542,156,37,66 +bisque,Bisque,#ffe4c4,255,228,196 +bistre,Bistre,#3d2b1f,61,43,31 +bittersweet,Bittersweet,#fe6f5e,254,111,94 +bittersweet_shimmer,"Bittersweet Shimmer",#bf4f51,191,79,81 +black,Black,#000,0,0,0 +black_bean,"Black Bean",#3d0c02,61,12,2 +black_leather_jacket,"Black Leather Jacket",#253529,37,53,41 +black_olive,"Black Olive",#3b3c36,59,60,54 +blanched_almond,"Blanched Almond",#ffebcd,255,235,205 +blast_off_bronze,"Blast-Off Bronze",#a57164,165,113,100 +bleu_de_france,"Bleu De France",#318ce7,49,140,231 +blizzard_blue,"Blizzard Blue",#ace5ee,172,229,238 +blond,Blond,#faf0be,250,240,190 +blue,Blue,#00f,0,0,255 +blue_bell,"Blue Bell",#a2a2d0,162,162,208 +blue_crayola,"Blue (Crayola)",#1f75fe,31,117,254 +blue_gray,"Blue Gray",#69c,102,153,204 +blue_green,Blue-Green,#0d98ba,13,152,186 +blue_munsell,"Blue (Munsell)",#0093af,0,147,175 +blue_ncs,"Blue (Ncs)",#0087bd,0,135,189 +blue_pigment,"Blue (Pigment)",#339,51,51,153 +blue_ryb,"Blue (Ryb)",#0247fe,2,71,254 +blue_sapphire,"Blue Sapphire",#126180,18,97,128 +blue_violet,Blue-Violet,#8a2be2,138,43,226 +blush,Blush,#de5d83,222,93,131 +bole,Bole,#79443b,121,68,59 +bondi_blue,"Bondi Blue",#0095b6,0,149,182 +bone,Bone,#e3dac9,227,218,201 +boston_university_red,"Boston University Red",#c00,204,0,0 +bottle_green,"Bottle Green",#006a4e,0,106,78 +boysenberry,Boysenberry,#873260,135,50,96 +brandeis_blue,"Brandeis Blue",#0070ff,0,112,255 +brass,Brass,#b5a642,181,166,66 +brick_red,"Brick Red",#cb4154,203,65,84 +bright_cerulean,"Bright Cerulean",#1dacd6,29,172,214 +bright_green,"Bright Green",#6f0,102,255,0 +bright_lavender,"Bright Lavender",#bf94e4,191,148,228 +bright_maroon,"Bright Maroon",#c32148,195,33,72 +bright_pink,"Bright Pink",#ff007f,255,0,127 +bright_turquoise,"Bright Turquoise",#08e8de,8,232,222 +bright_ube,"Bright Ube",#d19fe8,209,159,232 +brilliant_lavender,"Brilliant Lavender",#f4bbff,244,187,255 +brilliant_rose,"Brilliant Rose",#ff55a3,255,85,163 +brink_pink,"Brink Pink",#fb607f,251,96,127 +british_racing_green,"British Racing Green",#004225,0,66,37 +bronze,Bronze,#cd7f32,205,127,50 +brown_traditional,"Brown (Traditional)",#964b00,150,75,0 +brown_web,"Brown (Web)",#a52a2a,165,42,42 +bubble_gum,"Bubble Gum",#ffc1cc,255,193,204 +bubbles,Bubbles,#e7feff,231,254,255 +buff,Buff,#f0dc82,240,220,130 +bulgarian_rose,"Bulgarian Rose",#480607,72,6,7 +burgundy,Burgundy,#800020,128,0,32 +burlywood,Burlywood,#deb887,222,184,135 +burnt_orange,"Burnt Orange",#c50,204,85,0 +burnt_sienna,"Burnt Sienna",#e97451,233,116,81 +burnt_umber,"Burnt Umber",#8a3324,138,51,36 +byzantine,Byzantine,#bd33a4,189,51,164 +byzantium,Byzantium,#702963,112,41,99 +cadet,Cadet,#536872,83,104,114 +cadet_blue,"Cadet Blue",#5f9ea0,95,158,160 +cadet_grey,"Cadet Grey",#91a3b0,145,163,176 +cadmium_green,"Cadmium Green",#006b3c,0,107,60 +cadmium_orange,"Cadmium Orange",#ed872d,237,135,45 +cadmium_red,"Cadmium Red",#e30022,227,0,34 +cadmium_yellow,"Cadmium Yellow",#fff600,255,246,0 +caf_au_lait,"Café Au Lait",#a67b5b,166,123,91 +caf_noir,"Café Noir",#4b3621,75,54,33 +cal_poly_green,"Cal Poly Green",#1e4d2b,30,77,43 +cambridge_blue,"Cambridge Blue",#a3c1ad,163,193,173 +camel,Camel,#c19a6b,193,154,107 +cameo_pink,"Cameo Pink",#efbbcc,239,187,204 +camouflage_green,"Camouflage Green",#78866b,120,134,107 +canary_yellow,"Canary Yellow",#ffef00,255,239,0 +candy_apple_red,"Candy Apple Red",#ff0800,255,8,0 +candy_pink,"Candy Pink",#e4717a,228,113,122 +capri,Capri,#00bfff,0,191,255 +caput_mortuum,"Caput Mortuum",#592720,89,39,32 +cardinal,Cardinal,#c41e3a,196,30,58 +caribbean_green,"Caribbean Green",#0c9,0,204,153 +carmine,Carmine,#960018,150,0,24 +carmine_m_p,"Carmine (M&P)",#d70040,215,0,64 +carmine_pink,"Carmine Pink",#eb4c42,235,76,66 +carmine_red,"Carmine Red",#ff0038,255,0,56 +carnation_pink,"Carnation Pink",#ffa6c9,255,166,201 +carnelian,Carnelian,#b31b1b,179,27,27 +carolina_blue,"Carolina Blue",#99badd,153,186,221 +carrot_orange,"Carrot Orange",#ed9121,237,145,33 +catalina_blue,"Catalina Blue",#062a78,6,42,120 +ceil,Ceil,#92a1cf,146,161,207 +celadon,Celadon,#ace1af,172,225,175 +celadon_blue,"Celadon Blue",#007ba7,0,123,167 +celadon_green,"Celadon Green",#2f847c,47,132,124 +celeste_colour,"Celeste (Colour)",#b2ffff,178,255,255 +celestial_blue,"Celestial Blue",#4997d0,73,151,208 +cerise,Cerise,#de3163,222,49,99 +cerise_pink,"Cerise Pink",#ec3b83,236,59,131 +cerulean,Cerulean,#007ba7,0,123,167 +cerulean_blue,"Cerulean Blue",#2a52be,42,82,190 +cerulean_frost,"Cerulean Frost",#6d9bc3,109,155,195 +cg_blue,"Cg Blue",#007aa5,0,122,165 +cg_red,"Cg Red",#e03c31,224,60,49 +chamoisee,Chamoisee,#a0785a,160,120,90 +champagne,Champagne,#fad6a5,250,214,165 +charcoal,Charcoal,#36454f,54,69,79 +charm_pink,"Charm Pink",#e68fac,230,143,172 +chartreuse_traditional,"Chartreuse (Traditional)",#dfff00,223,255,0 +chartreuse_web,"Chartreuse (Web)",#7fff00,127,255,0 +cherry,Cherry,#de3163,222,49,99 +cherry_blossom_pink,"Cherry Blossom Pink",#ffb7c5,255,183,197 +chestnut,Chestnut,#cd5c5c,205,92,92 +china_pink,"China Pink",#de6fa1,222,111,161 +china_rose,"China Rose",#a8516e,168,81,110 +chinese_red,"Chinese Red",#aa381e,170,56,30 +chocolate_traditional,"Chocolate (Traditional)",#7b3f00,123,63,0 +chocolate_web,"Chocolate (Web)",#d2691e,210,105,30 +chrome_yellow,"Chrome Yellow",#ffa700,255,167,0 +cinereous,Cinereous,#98817b,152,129,123 +cinnabar,Cinnabar,#e34234,227,66,52 +cinnamon,Cinnamon,#d2691e,210,105,30 +citrine,Citrine,#e4d00a,228,208,10 +classic_rose,"Classic Rose",#fbcce7,251,204,231 +cobalt,Cobalt,#0047ab,0,71,171 +cocoa_brown,"Cocoa Brown",#d2691e,210,105,30 +coffee,Coffee,#6f4e37,111,78,55 +columbia_blue,"Columbia Blue",#9bddff,155,221,255 +congo_pink,"Congo Pink",#f88379,248,131,121 +cool_black,"Cool Black",#002e63,0,46,99 +cool_grey,"Cool Grey",#8c92ac,140,146,172 +copper,Copper,#b87333,184,115,51 +copper_crayola,"Copper (Crayola)",#da8a67,218,138,103 +copper_penny,"Copper Penny",#ad6f69,173,111,105 +copper_red,"Copper Red",#cb6d51,203,109,81 +copper_rose,"Copper Rose",#966,153,102,102 +coquelicot,Coquelicot,#ff3800,255,56,0 +coral,Coral,#ff7f50,255,127,80 +coral_pink,"Coral Pink",#f88379,248,131,121 +coral_red,"Coral Red",#ff4040,255,64,64 +cordovan,Cordovan,#893f45,137,63,69 +corn,Corn,#fbec5d,251,236,93 +cornell_red,"Cornell Red",#b31b1b,179,27,27 +cornflower_blue,"Cornflower Blue",#6495ed,100,149,237 +cornsilk,Cornsilk,#fff8dc,255,248,220 +cosmic_latte,"Cosmic Latte",#fff8e7,255,248,231 +cotton_candy,"Cotton Candy",#ffbcd9,255,188,217 +cream,Cream,#fffdd0,255,253,208 +crimson,Crimson,#dc143c,220,20,60 +crimson_glory,"Crimson Glory",#be0032,190,0,50 +cyan,Cyan,#0ff,0,255,255 +cyan_process,"Cyan (Process)",#00b7eb,0,183,235 +daffodil,Daffodil,#ffff31,255,255,49 +dandelion,Dandelion,#f0e130,240,225,48 +dark_blue,"Dark Blue",#00008b,0,0,139 +dark_brown,"Dark Brown",#654321,101,67,33 +dark_byzantium,"Dark Byzantium",#5d3954,93,57,84 +dark_candy_apple_red,"Dark Candy Apple Red",#a40000,164,0,0 +dark_cerulean,"Dark Cerulean",#08457e,8,69,126 +dark_chestnut,"Dark Chestnut",#986960,152,105,96 +dark_coral,"Dark Coral",#cd5b45,205,91,69 +dark_cyan,"Dark Cyan",#008b8b,0,139,139 +dark_electric_blue,"Dark Electric Blue",#536878,83,104,120 +dark_goldenrod,"Dark Goldenrod",#b8860b,184,134,11 +dark_gray,"Dark Gray",#a9a9a9,169,169,169 +dark_green,"Dark Green",#013220,1,50,32 +dark_imperial_blue,"Dark Imperial Blue",#00416a,0,65,106 +dark_jungle_green,"Dark Jungle Green",#1a2421,26,36,33 +dark_khaki,"Dark Khaki",#bdb76b,189,183,107 +dark_lava,"Dark Lava",#483c32,72,60,50 +dark_lavender,"Dark Lavender",#734f96,115,79,150 +dark_magenta,"Dark Magenta",#8b008b,139,0,139 +dark_midnight_blue,"Dark Midnight Blue",#036,0,51,102 +dark_olive_green,"Dark Olive Green",#556b2f,85,107,47 +dark_orange,"Dark Orange",#ff8c00,255,140,0 +dark_orchid,"Dark Orchid",#9932cc,153,50,204 +dark_pastel_blue,"Dark Pastel Blue",#779ecb,119,158,203 +dark_pastel_green,"Dark Pastel Green",#03c03c,3,192,60 +dark_pastel_purple,"Dark Pastel Purple",#966fd6,150,111,214 +dark_pastel_red,"Dark Pastel Red",#c23b22,194,59,34 +dark_pink,"Dark Pink",#e75480,231,84,128 +dark_powder_blue,"Dark Powder Blue",#039,0,51,153 +dark_raspberry,"Dark Raspberry",#872657,135,38,87 +dark_red,"Dark Red",#8b0000,139,0,0 +dark_salmon,"Dark Salmon",#e9967a,233,150,122 +dark_scarlet,"Dark Scarlet",#560319,86,3,25 +dark_sea_green,"Dark Sea Green",#8fbc8f,143,188,143 +dark_sienna,"Dark Sienna",#3c1414,60,20,20 +dark_slate_blue,"Dark Slate Blue",#483d8b,72,61,139 +dark_slate_gray,"Dark Slate Gray",#2f4f4f,47,79,79 +dark_spring_green,"Dark Spring Green",#177245,23,114,69 +dark_tan,"Dark Tan",#918151,145,129,81 +dark_tangerine,"Dark Tangerine",#ffa812,255,168,18 +dark_taupe,"Dark Taupe",#483c32,72,60,50 +dark_terra_cotta,"Dark Terra Cotta",#cc4e5c,204,78,92 +dark_turquoise,"Dark Turquoise",#00ced1,0,206,209 +dark_violet,"Dark Violet",#9400d3,148,0,211 +dark_yellow,"Dark Yellow",#9b870c,155,135,12 +dartmouth_green,"Dartmouth Green",#00703c,0,112,60 +davy_s_grey,"Davy'S Grey",#555,85,85,85 +debian_red,"Debian Red",#d70a53,215,10,83 +deep_carmine,"Deep Carmine",#a9203e,169,32,62 +deep_carmine_pink,"Deep Carmine Pink",#ef3038,239,48,56 +deep_carrot_orange,"Deep Carrot Orange",#e9692c,233,105,44 +deep_cerise,"Deep Cerise",#da3287,218,50,135 +deep_champagne,"Deep Champagne",#fad6a5,250,214,165 +deep_chestnut,"Deep Chestnut",#b94e48,185,78,72 +deep_coffee,"Deep Coffee",#704241,112,66,65 +deep_fuchsia,"Deep Fuchsia",#c154c1,193,84,193 +deep_jungle_green,"Deep Jungle Green",#004b49,0,75,73 +deep_lilac,"Deep Lilac",#95b,153,85,187 +deep_magenta,"Deep Magenta",#c0c,204,0,204 +deep_peach,"Deep Peach",#ffcba4,255,203,164 +deep_pink,"Deep Pink",#ff1493,255,20,147 +deep_ruby,"Deep Ruby",#843f5b,132,63,91 +deep_saffron,"Deep Saffron",#f93,255,153,51 +deep_sky_blue,"Deep Sky Blue",#00bfff,0,191,255 +deep_tuscan_red,"Deep Tuscan Red",#66424d,102,66,77 +denim,Denim,#1560bd,21,96,189 +desert,Desert,#c19a6b,193,154,107 +desert_sand,"Desert Sand",#edc9af,237,201,175 +dim_gray,"Dim Gray",#696969,105,105,105 +dodger_blue,"Dodger Blue",#1e90ff,30,144,255 +dogwood_rose,"Dogwood Rose",#d71868,215,24,104 +dollar_bill,"Dollar Bill",#85bb65,133,187,101 +drab,Drab,#967117,150,113,23 +duke_blue,"Duke Blue",#00009c,0,0,156 +earth_yellow,"Earth Yellow",#e1a95f,225,169,95 +ebony,Ebony,#555d50,85,93,80 +ecru,Ecru,#c2b280,194,178,128 +eggplant,Eggplant,#614051,97,64,81 +eggshell,Eggshell,#f0ead6,240,234,214 +egyptian_blue,"Egyptian Blue",#1034a6,16,52,166 +electric_blue,"Electric Blue",#7df9ff,125,249,255 +electric_crimson,"Electric Crimson",#ff003f,255,0,63 +electric_cyan,"Electric Cyan",#0ff,0,255,255 +electric_green,"Electric Green",#0f0,0,255,0 +electric_indigo,"Electric Indigo",#6f00ff,111,0,255 +electric_lavender,"Electric Lavender",#f4bbff,244,187,255 +electric_lime,"Electric Lime",#cf0,204,255,0 +electric_purple,"Electric Purple",#bf00ff,191,0,255 +electric_ultramarine,"Electric Ultramarine",#3f00ff,63,0,255 +electric_violet,"Electric Violet",#8f00ff,143,0,255 +electric_yellow,"Electric Yellow",#ff0,255,255,0 +emerald,Emerald,#50c878,80,200,120 +english_lavender,"English Lavender",#b48395,180,131,149 +eton_blue,"Eton Blue",#96c8a2,150,200,162 +fallow,Fallow,#c19a6b,193,154,107 +falu_red,"Falu Red",#801818,128,24,24 +fandango,Fandango,#b53389,181,51,137 +fashion_fuchsia,"Fashion Fuchsia",#f400a1,244,0,161 +fawn,Fawn,#e5aa70,229,170,112 +feldgrau,Feldgrau,#4d5d53,77,93,83 +fern_green,"Fern Green",#4f7942,79,121,66 +ferrari_red,"Ferrari Red",#ff2800,255,40,0 +field_drab,"Field Drab",#6c541e,108,84,30 +fire_engine_red,"Fire Engine Red",#ce2029,206,32,41 +firebrick,Firebrick,#b22222,178,34,34 +flame,Flame,#e25822,226,88,34 +flamingo_pink,"Flamingo Pink",#fc8eac,252,142,172 +flavescent,Flavescent,#f7e98e,247,233,142 +flax,Flax,#eedc82,238,220,130 +floral_white,"Floral White",#fffaf0,255,250,240 +fluorescent_orange,"Fluorescent Orange",#ffbf00,255,191,0 +fluorescent_pink,"Fluorescent Pink",#ff1493,255,20,147 +fluorescent_yellow,"Fluorescent Yellow",#cf0,204,255,0 +folly,Folly,#ff004f,255,0,79 +forest_green_traditional,"Forest Green (Traditional)",#014421,1,68,33 +forest_green_web,"Forest Green (Web)",#228b22,34,139,34 +french_beige,"French Beige",#a67b5b,166,123,91 +french_blue,"French Blue",#0072bb,0,114,187 +french_lilac,"French Lilac",#86608e,134,96,142 +french_lime,"French Lime",#cf0,204,255,0 +french_raspberry,"French Raspberry",#c72c48,199,44,72 +french_rose,"French Rose",#f64a8a,246,74,138 +fuchsia,Fuchsia,#f0f,255,0,255 +fuchsia_crayola,"Fuchsia (Crayola)",#c154c1,193,84,193 +fuchsia_pink,"Fuchsia Pink",#f7f,255,119,255 +fuchsia_rose,"Fuchsia Rose",#c74375,199,67,117 +fulvous,Fulvous,#e48400,228,132,0 +fuzzy_wuzzy,"Fuzzy Wuzzy",#c66,204,102,102 +gainsboro,Gainsboro,#dcdcdc,220,220,220 +gamboge,Gamboge,#e49b0f,228,155,15 +ghost_white,"Ghost White",#f8f8ff,248,248,255 +ginger,Ginger,#b06500,176,101,0 +glaucous,Glaucous,#6082b6,96,130,182 +glitter,Glitter,#e6e8fa,230,232,250 +gold_metallic,"Gold (Metallic)",#d4af37,212,175,55 +gold_web_golden,"Gold (Web) (Golden)",#ffd700,255,215,0 +golden_brown,"Golden Brown",#996515,153,101,21 +golden_poppy,"Golden Poppy",#fcc200,252,194,0 +golden_yellow,"Golden Yellow",#ffdf00,255,223,0 +goldenrod,Goldenrod,#daa520,218,165,32 +granny_smith_apple,"Granny Smith Apple",#a8e4a0,168,228,160 +gray,Gray,#808080,128,128,128 +gray_asparagus,Gray-Asparagus,#465945,70,89,69 +gray_html_css_gray,"Gray (Html/Css Gray)",#808080,128,128,128 +gray_x11_gray,"Gray (X11 Gray)",#bebebe,190,190,190 +green,"Green (Color Wheel) (X11 Green)",#0f0,0,255,0 +green_crayola,"Green (Crayola)",#1cac78,28,172,120 +green_html_css_green,"Green (Html/Css Green)",#008000,0,128,0 +green_munsell,"Green (Munsell)",#00a877,0,168,119 +green_ncs,"Green (Ncs)",#009f6b,0,159,107 +green_pigment,"Green (Pigment)",#00a550,0,165,80 +green_ryb,"Green (Ryb)",#66b032,102,176,50 +green_yellow,Green-Yellow,#adff2f,173,255,47 +grullo,Grullo,#a99a86,169,154,134 +guppie_green,"Guppie Green",#00ff7f,0,255,127 +halay_be,"Halayà úBe",#663854,102,56,84 +han_blue,"Han Blue",#446ccf,68,108,207 +han_purple,"Han Purple",#5218fa,82,24,250 +hansa_yellow,"Hansa Yellow",#e9d66b,233,214,107 +harlequin,Harlequin,#3fff00,63,255,0 +harvard_crimson,"Harvard Crimson",#c90016,201,0,22 +harvest_gold,"Harvest Gold",#da9100,218,145,0 +heart_gold,"Heart Gold",#808000,128,128,0 +heliotrope,Heliotrope,#df73ff,223,115,255 +hollywood_cerise,"Hollywood Cerise",#f400a1,244,0,161 +honeydew,Honeydew,#f0fff0,240,255,240 +honolulu_blue,"Honolulu Blue",#007fbf,0,127,191 +hooker_s_green,"Hooker'S Green",#49796b,73,121,107 +hot_magenta,"Hot Magenta",#ff1dce,255,29,206 +hot_pink,"Hot Pink",#ff69b4,255,105,180 +hunter_green,"Hunter Green",#355e3b,53,94,59 +iceberg,Iceberg,#71a6d2,113,166,210 +icterine,Icterine,#fcf75e,252,247,94 +imperial_blue,"Imperial Blue",#002395,0,35,149 +inchworm,Inchworm,#b2ec5d,178,236,93 +india_green,"India Green",#138808,19,136,8 +indian_red,"Indian Red",#cd5c5c,205,92,92 +indian_yellow,"Indian Yellow",#e3a857,227,168,87 +indigo,Indigo,#6f00ff,111,0,255 +indigo_dye,"Indigo (Dye)",#00416a,0,65,106 +indigo_web,"Indigo (Web)",#4b0082,75,0,130 +international_klein_blue,"International Klein Blue",#002fa7,0,47,167 +international_orange_aerospace,"International Orange (Aerospace)",#ff4f00,255,79,0 +international_orange_engineering,"International Orange (Engineering)",#ba160c,186,22,12 +international_orange_golden_gate_bridge,"International Orange (Golden Gate Bridge)",#c0362c,192,54,44 +iris,Iris,#5a4fcf,90,79,207 +isabelline,Isabelline,#f4f0ec,244,240,236 +islamic_green,"Islamic Green",#009000,0,144,0 +ivory,Ivory,#fffff0,255,255,240 +jade,Jade,#00a86b,0,168,107 +jasmine,Jasmine,#f8de7e,248,222,126 +jasper,Jasper,#d73b3e,215,59,62 +jazzberry_jam,"Jazzberry Jam",#a50b5e,165,11,94 +jet,Jet,#343434,52,52,52 +jonquil,Jonquil,#fada5e,250,218,94 +june_bud,"June Bud",#bdda57,189,218,87 +jungle_green,"Jungle Green",#29ab87,41,171,135 +kelly_green,"Kelly Green",#4cbb17,76,187,23 +kenyan_copper,"Kenyan Copper",#7c1c05,124,28,5 +khaki_html_css_khaki,"Khaki (Html/Css) (Khaki)",#c3b091,195,176,145 +khaki_x11_light_khaki,"Khaki (X11) (Light Khaki)",#f0e68c,240,230,140 +ku_crimson,"Ku Crimson",#e8000d,232,0,13 +la_salle_green,"La Salle Green",#087830,8,120,48 +languid_lavender,"Languid Lavender",#d6cadd,214,202,221 +lapis_lazuli,"Lapis Lazuli",#26619c,38,97,156 +laser_lemon,"Laser Lemon",#fefe22,254,254,34 +laurel_green,"Laurel Green",#a9ba9d,169,186,157 +lava,Lava,#cf1020,207,16,32 +lavender_blue,"Lavender Blue",#ccf,204,204,255 +lavender_blush,"Lavender Blush",#fff0f5,255,240,245 +lavender_floral,"Lavender (Floral)",#b57edc,181,126,220 +lavender_gray,"Lavender Gray",#c4c3d0,196,195,208 +lavender_indigo,"Lavender Indigo",#9457eb,148,87,235 +lavender_magenta,"Lavender Magenta",#ee82ee,238,130,238 +lavender_mist,"Lavender Mist",#e6e6fa,230,230,250 +lavender_pink,"Lavender Pink",#fbaed2,251,174,210 +lavender_purple,"Lavender Purple",#967bb6,150,123,182 +lavender_rose,"Lavender Rose",#fba0e3,251,160,227 +lavender_web,"Lavender (Web)",#e6e6fa,230,230,250 +lawn_green,"Lawn Green",#7cfc00,124,252,0 +lemon,Lemon,#fff700,255,247,0 +lemon_chiffon,"Lemon Chiffon",#fffacd,255,250,205 +lemon_lime,"Lemon Lime",#e3ff00,227,255,0 +licorice,Licorice,#1a1110,26,17,16 +light_apricot,"Light Apricot",#fdd5b1,253,213,177 +light_blue,"Light Blue",#add8e6,173,216,230 +light_brown,"Light Brown",#b5651d,181,101,29 +light_carmine_pink,"Light Carmine Pink",#e66771,230,103,113 +light_coral,"Light Coral",#f08080,240,128,128 +light_cornflower_blue,"Light Cornflower Blue",#93ccea,147,204,234 +light_crimson,"Light Crimson",#f56991,245,105,145 +light_cyan,"Light Cyan",#e0ffff,224,255,255 +light_fuchsia_pink,"Light Fuchsia Pink",#f984ef,249,132,239 +light_goldenrod_yellow,"Light Goldenrod Yellow",#fafad2,250,250,210 +light_gray,"Light Gray",#d3d3d3,211,211,211 +light_green,"Light Green",#90ee90,144,238,144 +light_khaki,"Light Khaki",#f0e68c,240,230,140 +light_pastel_purple,"Light Pastel Purple",#b19cd9,177,156,217 +light_pink,"Light Pink",#ffb6c1,255,182,193 +light_red_ochre,"Light Red Ochre",#e97451,233,116,81 +light_salmon,"Light Salmon",#ffa07a,255,160,122 +light_salmon_pink,"Light Salmon Pink",#f99,255,153,153 +light_sea_green,"Light Sea Green",#20b2aa,32,178,170 +light_sky_blue,"Light Sky Blue",#87cefa,135,206,250 +light_slate_gray,"Light Slate Gray",#789,119,136,153 +light_taupe,"Light Taupe",#b38b6d,179,139,109 +light_thulian_pink,"Light Thulian Pink",#e68fac,230,143,172 +light_yellow,"Light Yellow",#ffffe0,255,255,224 +lilac,Lilac,#c8a2c8,200,162,200 +lime,"Lime (Color Wheel)",#bfff00,191,255,0 +lime_green,"Lime Green",#32cd32,50,205,50 +lime_web_x11_green,"Lime (Web) (X11 Green)",#0f0,0,255,0 +limerick,Limerick,#9dc209,157,194,9 +lincoln_green,"Lincoln Green",#195905,25,89,5 +linen,Linen,#faf0e6,250,240,230 +lion,Lion,#c19a6b,193,154,107 +little_boy_blue,"Little Boy Blue",#6ca0dc,108,160,220 +liver,Liver,#534b4f,83,75,79 +lust,Lust,#e62020,230,32,32 +magenta,Magenta,#f0f,255,0,255 +magenta_dye,"Magenta (Dye)",#ca1f7b,202,31,123 +magenta_process,"Magenta (Process)",#ff0090,255,0,144 +magic_mint,"Magic Mint",#aaf0d1,170,240,209 +magnolia,Magnolia,#f8f4ff,248,244,255 +mahogany,Mahogany,#c04000,192,64,0 +maize,Maize,#fbec5d,251,236,93 +majorelle_blue,"Majorelle Blue",#6050dc,96,80,220 +malachite,Malachite,#0bda51,11,218,81 +manatee,Manatee,#979aaa,151,154,170 +mango_tango,"Mango Tango",#ff8243,255,130,67 +mantis,Mantis,#74c365,116,195,101 +mardi_gras,"Mardi Gras",#880085,136,0,133 +maroon_crayola,"Maroon (Crayola)",#c32148,195,33,72 +maroon_html_css,"Maroon (Html/Css)",#800000,128,0,0 +maroon_x11,"Maroon (X11)",#b03060,176,48,96 +mauve,Mauve,#e0b0ff,224,176,255 +mauve_taupe,"Mauve Taupe",#915f6d,145,95,109 +mauvelous,Mauvelous,#ef98aa,239,152,170 +maya_blue,"Maya Blue",#73c2fb,115,194,251 +meat_brown,"Meat Brown",#e5b73b,229,183,59 +medium_aquamarine,"Medium Aquamarine",#6da,102,221,170 +medium_blue,"Medium Blue",#0000cd,0,0,205 +medium_candy_apple_red,"Medium Candy Apple Red",#e2062c,226,6,44 +medium_carmine,"Medium Carmine",#af4035,175,64,53 +medium_champagne,"Medium Champagne",#f3e5ab,243,229,171 +medium_electric_blue,"Medium Electric Blue",#035096,3,80,150 +medium_jungle_green,"Medium Jungle Green",#1c352d,28,53,45 +medium_lavender_magenta,"Medium Lavender Magenta",#dda0dd,221,160,221 +medium_orchid,"Medium Orchid",#ba55d3,186,85,211 +medium_persian_blue,"Medium Persian Blue",#0067a5,0,103,165 +medium_purple,"Medium Purple",#9370db,147,112,219 +medium_red_violet,"Medium Red-Violet",#bb3385,187,51,133 +medium_ruby,"Medium Ruby",#aa4069,170,64,105 +medium_sea_green,"Medium Sea Green",#3cb371,60,179,113 +medium_slate_blue,"Medium Slate Blue",#7b68ee,123,104,238 +medium_spring_bud,"Medium Spring Bud",#c9dc87,201,220,135 +medium_spring_green,"Medium Spring Green",#00fa9a,0,250,154 +medium_taupe,"Medium Taupe",#674c47,103,76,71 +medium_turquoise,"Medium Turquoise",#48d1cc,72,209,204 +medium_tuscan_red,"Medium Tuscan Red",#79443b,121,68,59 +medium_vermilion,"Medium Vermilion",#d9603b,217,96,59 +medium_violet_red,"Medium Violet-Red",#c71585,199,21,133 +mellow_apricot,"Mellow Apricot",#f8b878,248,184,120 +mellow_yellow,"Mellow Yellow",#f8de7e,248,222,126 +melon,Melon,#fdbcb4,253,188,180 +midnight_blue,"Midnight Blue",#191970,25,25,112 +midnight_green_eagle_green,"Midnight Green (Eagle Green)",#004953,0,73,83 +mikado_yellow,"Mikado Yellow",#ffc40c,255,196,12 +mint,Mint,#3eb489,62,180,137 +mint_cream,"Mint Cream",#f5fffa,245,255,250 +mint_green,"Mint Green",#98ff98,152,255,152 +misty_rose,"Misty Rose",#ffe4e1,255,228,225 +moccasin,Moccasin,#faebd7,250,235,215 +mode_beige,"Mode Beige",#967117,150,113,23 +moonstone_blue,"Moonstone Blue",#73a9c2,115,169,194 +mordant_red_19,"Mordant Red 19",#ae0c00,174,12,0 +moss_green,"Moss Green",#addfad,173,223,173 +mountain_meadow,"Mountain Meadow",#30ba8f,48,186,143 +mountbatten_pink,"Mountbatten Pink",#997a8d,153,122,141 +msu_green,"Msu Green",#18453b,24,69,59 +mulberry,Mulberry,#c54b8c,197,75,140 +mustard,Mustard,#ffdb58,255,219,88 +myrtle,Myrtle,#21421e,33,66,30 +nadeshiko_pink,"Nadeshiko Pink",#f6adc6,246,173,198 +napier_green,"Napier Green",#2a8000,42,128,0 +naples_yellow,"Naples Yellow",#fada5e,250,218,94 +navajo_white,"Navajo White",#ffdead,255,222,173 +navy_blue,"Navy Blue",#000080,0,0,128 +neon_carrot,"Neon Carrot",#ffa343,255,163,67 +neon_fuchsia,"Neon Fuchsia",#fe4164,254,65,100 +neon_green,"Neon Green",#39ff14,57,255,20 +new_york_pink,"New York Pink",#d7837f,215,131,127 +non_photo_blue,"Non-Photo Blue",#a4dded,164,221,237 +north_texas_green,"North Texas Green",#059033,5,144,51 +ocean_boat_blue,"Ocean Boat Blue",#0077be,0,119,190 +ochre,Ochre,#c72,204,119,34 +office_green,"Office Green",#008000,0,128,0 +old_gold,"Old Gold",#cfb53b,207,181,59 +old_lace,"Old Lace",#fdf5e6,253,245,230 +old_lavender,"Old Lavender",#796878,121,104,120 +old_mauve,"Old Mauve",#673147,103,49,71 +old_rose,"Old Rose",#c08081,192,128,129 +olive,Olive,#808000,128,128,0 +olive_drab_7,"Olive Drab #7",#3c341f,60,52,31 +olive_drab_web_olive_drab_3,"Olive Drab (Web) (Olive Drab #3)",#6b8e23,107,142,35 +olivine,Olivine,#9ab973,154,185,115 +onyx,Onyx,#353839,53,56,57 +opera_mauve,"Opera Mauve",#b784a7,183,132,167 +orange,"Orange (Color Wheel)",#ff7f00,255,127,0 +orange_peel,"Orange Peel",#ff9f00,255,159,0 +orange_red,Orange-Red,#ff4500,255,69,0 +orange_ryb,"Orange (Ryb)",#fb9902,251,153,2 +orange_web_color,"Orange (Web Color)",#ffa500,255,165,0 +orchid,Orchid,#da70d6,218,112,214 +otter_brown,"Otter Brown",#654321,101,67,33 +ou_crimson_red,"Ou Crimson Red",#900,153,0,0 +outer_space,"Outer Space",#414a4c,65,74,76 +outrageous_orange,"Outrageous Orange",#ff6e4a,255,110,74 +oxford_blue,"Oxford Blue",#002147,0,33,71 +pakistan_green,"Pakistan Green",#060,0,102,0 +palatinate_blue,"Palatinate Blue",#273be2,39,59,226 +palatinate_purple,"Palatinate Purple",#682860,104,40,96 +pale_aqua,"Pale Aqua",#bcd4e6,188,212,230 +pale_blue,"Pale Blue",#afeeee,175,238,238 +pale_brown,"Pale Brown",#987654,152,118,84 +pale_carmine,"Pale Carmine",#af4035,175,64,53 +pale_cerulean,"Pale Cerulean",#9bc4e2,155,196,226 +pale_chestnut,"Pale Chestnut",#ddadaf,221,173,175 +pale_copper,"Pale Copper",#da8a67,218,138,103 +pale_cornflower_blue,"Pale Cornflower Blue",#abcdef,171,205,239 +pale_gold,"Pale Gold",#e6be8a,230,190,138 +pale_goldenrod,"Pale Goldenrod",#eee8aa,238,232,170 +pale_green,"Pale Green",#98fb98,152,251,152 +pale_lavender,"Pale Lavender",#dcd0ff,220,208,255 +pale_magenta,"Pale Magenta",#f984e5,249,132,229 +pale_pink,"Pale Pink",#fadadd,250,218,221 +pale_plum,"Pale Plum",#dda0dd,221,160,221 +pale_red_violet,"Pale Red-Violet",#db7093,219,112,147 +pale_robin_egg_blue,"Pale Robin Egg Blue",#96ded1,150,222,209 +pale_silver,"Pale Silver",#c9c0bb,201,192,187 +pale_spring_bud,"Pale Spring Bud",#ecebbd,236,235,189 +pale_taupe,"Pale Taupe",#bc987e,188,152,126 +pale_violet_red,"Pale Violet-Red",#db7093,219,112,147 +pansy_purple,"Pansy Purple",#78184a,120,24,74 +papaya_whip,"Papaya Whip",#ffefd5,255,239,213 +paris_green,"Paris Green",#50c878,80,200,120 +pastel_blue,"Pastel Blue",#aec6cf,174,198,207 +pastel_brown,"Pastel Brown",#836953,131,105,83 +pastel_gray,"Pastel Gray",#cfcfc4,207,207,196 +pastel_green,"Pastel Green",#7d7,119,221,119 +pastel_magenta,"Pastel Magenta",#f49ac2,244,154,194 +pastel_orange,"Pastel Orange",#ffb347,255,179,71 +pastel_pink,"Pastel Pink",#dea5a4,222,165,164 +pastel_purple,"Pastel Purple",#b39eb5,179,158,181 +pastel_red,"Pastel Red",#ff6961,255,105,97 +pastel_violet,"Pastel Violet",#cb99c9,203,153,201 +pastel_yellow,"Pastel Yellow",#fdfd96,253,253,150 +patriarch,Patriarch,#800080,128,0,128 +payne_s_grey,"Payne'S Grey",#536878,83,104,120 +peach,Peach,#ffe5b4,255,229,180 +peach_crayola,"Peach (Crayola)",#ffcba4,255,203,164 +peach_orange,Peach-Orange,#fc9,255,204,153 +peach_puff,"Peach Puff",#ffdab9,255,218,185 +peach_yellow,Peach-Yellow,#fadfad,250,223,173 +pear,Pear,#d1e231,209,226,49 +pearl,Pearl,#eae0c8,234,224,200 +pearl_aqua,"Pearl Aqua",#88d8c0,136,216,192 +pearly_purple,"Pearly Purple",#b768a2,183,104,162 +peridot,Peridot,#e6e200,230,226,0 +periwinkle,Periwinkle,#ccf,204,204,255 +persian_blue,"Persian Blue",#1c39bb,28,57,187 +persian_green,"Persian Green",#00a693,0,166,147 +persian_indigo,"Persian Indigo",#32127a,50,18,122 +persian_orange,"Persian Orange",#d99058,217,144,88 +persian_pink,"Persian Pink",#f77fbe,247,127,190 +persian_plum,"Persian Plum",#701c1c,112,28,28 +persian_red,"Persian Red",#c33,204,51,51 +persian_rose,"Persian Rose",#fe28a2,254,40,162 +persimmon,Persimmon,#ec5800,236,88,0 +peru,Peru,#cd853f,205,133,63 +phlox,Phlox,#df00ff,223,0,255 +phthalo_blue,"Phthalo Blue",#000f89,0,15,137 +phthalo_green,"Phthalo Green",#123524,18,53,36 +piggy_pink,"Piggy Pink",#fddde6,253,221,230 +pine_green,"Pine Green",#01796f,1,121,111 +pink,Pink,#ffc0cb,255,192,203 +pink_lace,"Pink Lace",#ffddf4,255,221,244 +pink_orange,Pink-Orange,#f96,255,153,102 +pink_pearl,"Pink Pearl",#e7accf,231,172,207 +pink_sherbet,"Pink Sherbet",#f78fa7,247,143,167 +pistachio,Pistachio,#93c572,147,197,114 +platinum,Platinum,#e5e4e2,229,228,226 +plum_traditional,"Plum (Traditional)",#8e4585,142,69,133 +plum_web,"Plum (Web)",#dda0dd,221,160,221 +portland_orange,"Portland Orange",#ff5a36,255,90,54 +powder_blue_web,"Powder Blue (Web)",#b0e0e6,176,224,230 +princeton_orange,"Princeton Orange",#ff8f00,255,143,0 +prune,Prune,#701c1c,112,28,28 +prussian_blue,"Prussian Blue",#003153,0,49,83 +psychedelic_purple,"Psychedelic Purple",#df00ff,223,0,255 +puce,Puce,#c89,204,136,153 +pumpkin,Pumpkin,#ff7518,255,117,24 +purple_heart,"Purple Heart",#69359c,105,53,156 +purple_html_css,"Purple (Html/Css)",#800080,128,0,128 +purple_mountain_majesty,"Purple Mountain Majesty",#9678b6,150,120,182 +purple_munsell,"Purple (Munsell)",#9f00c5,159,0,197 +purple_pizzazz,"Purple Pizzazz",#fe4eda,254,78,218 +purple_taupe,"Purple Taupe",#50404d,80,64,77 +purple_x11,"Purple (X11)",#a020f0,160,32,240 +quartz,Quartz,#51484f,81,72,79 +rackley,Rackley,#5d8aa8,93,138,168 +radical_red,"Radical Red",#ff355e,255,53,94 +rajah,Rajah,#fbab60,251,171,96 +raspberry,Raspberry,#e30b5d,227,11,93 +raspberry_glace,"Raspberry Glace",#915f6d,145,95,109 +raspberry_pink,"Raspberry Pink",#e25098,226,80,152 +raspberry_rose,"Raspberry Rose",#b3446c,179,68,108 +raw_umber,"Raw Umber",#826644,130,102,68 +razzle_dazzle_rose,"Razzle Dazzle Rose",#f3c,255,51,204 +razzmatazz,Razzmatazz,#e3256b,227,37,107 +red,Red,#f00,255,0,0 +red_brown,Red-Brown,#a52a2a,165,42,42 +red_devil,"Red Devil",#860111,134,1,17 +red_munsell,"Red (Munsell)",#f2003c,242,0,60 +red_ncs,"Red (Ncs)",#c40233,196,2,51 +red_orange,Red-Orange,#ff5349,255,83,73 +red_pigment,"Red (Pigment)",#ed1c24,237,28,36 +red_ryb,"Red (Ryb)",#fe2712,254,39,18 +red_violet,Red-Violet,#c71585,199,21,133 +redwood,Redwood,#ab4e52,171,78,82 +regalia,Regalia,#522d80,82,45,128 +resolution_blue,"Resolution Blue",#002387,0,35,135 +rich_black,"Rich Black",#004040,0,64,64 +rich_brilliant_lavender,"Rich Brilliant Lavender",#f1a7fe,241,167,254 +rich_carmine,"Rich Carmine",#d70040,215,0,64 +rich_electric_blue,"Rich Electric Blue",#0892d0,8,146,208 +rich_lavender,"Rich Lavender",#a76bcf,167,107,207 +rich_lilac,"Rich Lilac",#b666d2,182,102,210 +rich_maroon,"Rich Maroon",#b03060,176,48,96 +rifle_green,"Rifle Green",#414833,65,72,51 +robin_egg_blue,"Robin Egg Blue",#0cc,0,204,204 +rose,Rose,#ff007f,255,0,127 +rose_bonbon,"Rose Bonbon",#f9429e,249,66,158 +rose_ebony,"Rose Ebony",#674846,103,72,70 +rose_gold,"Rose Gold",#b76e79,183,110,121 +rose_madder,"Rose Madder",#e32636,227,38,54 +rose_pink,"Rose Pink",#f6c,255,102,204 +rose_quartz,"Rose Quartz",#aa98a9,170,152,169 +rose_taupe,"Rose Taupe",#905d5d,144,93,93 +rose_vale,"Rose Vale",#ab4e52,171,78,82 +rosewood,Rosewood,#65000b,101,0,11 +rosso_corsa,"Rosso Corsa",#d40000,212,0,0 +rosy_brown,"Rosy Brown",#bc8f8f,188,143,143 +royal_azure,"Royal Azure",#0038a8,0,56,168 +royal_blue_traditional,"Royal Blue (Traditional)",#002366,0,35,102 +royal_blue_web,"Royal Blue (Web)",#4169e1,65,105,225 +royal_fuchsia,"Royal Fuchsia",#ca2c92,202,44,146 +royal_purple,"Royal Purple",#7851a9,120,81,169 +royal_yellow,"Royal Yellow",#fada5e,250,218,94 +rubine_red,"Rubine Red",#d10056,209,0,86 +ruby,Ruby,#e0115f,224,17,95 +ruby_red,"Ruby Red",#9b111e,155,17,30 +ruddy,Ruddy,#ff0028,255,0,40 +ruddy_brown,"Ruddy Brown",#bb6528,187,101,40 +ruddy_pink,"Ruddy Pink",#e18e96,225,142,150 +rufous,Rufous,#a81c07,168,28,7 +russet,Russet,#80461b,128,70,27 +rust,Rust,#b7410e,183,65,14 +rusty_red,"Rusty Red",#da2c43,218,44,67 +sacramento_state_green,"Sacramento State Green",#00563f,0,86,63 +saddle_brown,"Saddle Brown",#8b4513,139,69,19 +safety_orange_blaze_orange,"Safety Orange (Blaze Orange)",#ff6700,255,103,0 +saffron,Saffron,#f4c430,244,196,48 +salmon,Salmon,#ff8c69,255,140,105 +salmon_pink,"Salmon Pink",#ff91a4,255,145,164 +sand,Sand,#c2b280,194,178,128 +sand_dune,"Sand Dune",#967117,150,113,23 +sandstorm,Sandstorm,#ecd540,236,213,64 +sandy_brown,"Sandy Brown",#f4a460,244,164,96 +sandy_taupe,"Sandy Taupe",#967117,150,113,23 +sangria,Sangria,#92000a,146,0,10 +sap_green,"Sap Green",#507d2a,80,125,42 +sapphire,Sapphire,#0f52ba,15,82,186 +sapphire_blue,"Sapphire Blue",#0067a5,0,103,165 +satin_sheen_gold,"Satin Sheen Gold",#cba135,203,161,53 +scarlet,Scarlet,#ff2400,255,36,0 +scarlet_crayola,"Scarlet (Crayola)",#fd0e35,253,14,53 +school_bus_yellow,"School Bus Yellow",#ffd800,255,216,0 +screamin_green,"Screamin' Green",#76ff7a,118,255,122 +sea_blue,"Sea Blue",#006994,0,105,148 +sea_green,"Sea Green",#2e8b57,46,139,87 +seal_brown,"Seal Brown",#321414,50,20,20 +seashell,Seashell,#fff5ee,255,245,238 +selective_yellow,"Selective Yellow",#ffba00,255,186,0 +sepia,Sepia,#704214,112,66,20 +shadow,Shadow,#8a795d,138,121,93 +shamrock_green,"Shamrock Green",#009e60,0,158,96 +shocking_pink,"Shocking Pink",#fc0fc0,252,15,192 +shocking_pink_crayola,"Shocking Pink (Crayola)",#ff6fff,255,111,255 +sienna,Sienna,#882d17,136,45,23 +silver,Silver,#c0c0c0,192,192,192 +sinopia,Sinopia,#cb410b,203,65,11 +skobeloff,Skobeloff,#007474,0,116,116 +sky_blue,"Sky Blue",#87ceeb,135,206,235 +sky_magenta,"Sky Magenta",#cf71af,207,113,175 +slate_blue,"Slate Blue",#6a5acd,106,90,205 +slate_gray,"Slate Gray",#708090,112,128,144 +smalt_dark_powder_blue,"Smalt (Dark Powder Blue)",#039,0,51,153 +smokey_topaz,"Smokey Topaz",#933d41,147,61,65 +smoky_black,"Smoky Black",#100c08,16,12,8 +snow,Snow,#fffafa,255,250,250 +spiro_disco_ball,"Spiro Disco Ball",#0fc0fc,15,192,252 +spring_bud,"Spring Bud",#a7fc00,167,252,0 +spring_green,"Spring Green",#00ff7f,0,255,127 +st_patrick_s_blue,"St. Patrick'S Blue",#23297a,35,41,122 +steel_blue,"Steel Blue",#4682b4,70,130,180 +stil_de_grain_yellow,"Stil De Grain Yellow",#fada5e,250,218,94 +stizza,Stizza,#900,153,0,0 +stormcloud,Stormcloud,#4f666a,79,102,106 +straw,Straw,#e4d96f,228,217,111 +sunglow,Sunglow,#fc3,255,204,51 +sunset,Sunset,#fad6a5,250,214,165 +tan,Tan,#d2b48c,210,180,140 +tangelo,Tangelo,#f94d00,249,77,0 +tangerine,Tangerine,#f28500,242,133,0 +tangerine_yellow,"Tangerine Yellow",#fc0,255,204,0 +tango_pink,"Tango Pink",#e4717a,228,113,122 +taupe,Taupe,#483c32,72,60,50 +taupe_gray,"Taupe Gray",#8b8589,139,133,137 +tea_green,"Tea Green",#d0f0c0,208,240,192 +tea_rose_orange,"Tea Rose (Orange)",#f88379,248,131,121 +tea_rose_rose,"Tea Rose (Rose)",#f4c2c2,244,194,194 +teal,Teal,#008080,0,128,128 +teal_blue,"Teal Blue",#367588,54,117,136 +teal_green,"Teal Green",#00827f,0,130,127 +telemagenta,Telemagenta,#cf3476,207,52,118 +tenn_tawny,"Tenné (Tawny)",#cd5700,205,87,0 +terra_cotta,"Terra Cotta",#e2725b,226,114,91 +thistle,Thistle,#d8bfd8,216,191,216 +thulian_pink,"Thulian Pink",#de6fa1,222,111,161 +tickle_me_pink,"Tickle Me Pink",#fc89ac,252,137,172 +tiffany_blue,"Tiffany Blue",#0abab5,10,186,181 +tiger_s_eye,"Tiger'S Eye",#e08d3c,224,141,60 +timberwolf,Timberwolf,#dbd7d2,219,215,210 +titanium_yellow,"Titanium Yellow",#eee600,238,230,0 +tomato,Tomato,#ff6347,255,99,71 +toolbox,Toolbox,#746cc0,116,108,192 +topaz,Topaz,#ffc87c,255,200,124 +tractor_red,"Tractor Red",#fd0e35,253,14,53 +trolley_grey,"Trolley Grey",#808080,128,128,128 +tropical_rain_forest,"Tropical Rain Forest",#00755e,0,117,94 +true_blue,"True Blue",#0073cf,0,115,207 +tufts_blue,"Tufts Blue",#417dc1,65,125,193 +tumbleweed,Tumbleweed,#deaa88,222,170,136 +turkish_rose,"Turkish Rose",#b57281,181,114,129 +turquoise,Turquoise,#30d5c8,48,213,200 +turquoise_blue,"Turquoise Blue",#00ffef,0,255,239 +turquoise_green,"Turquoise Green",#a0d6b4,160,214,180 +tuscan_red,"Tuscan Red",#7c4848,124,72,72 +twilight_lavender,"Twilight Lavender",#8a496b,138,73,107 +tyrian_purple,"Tyrian Purple",#66023c,102,2,60 +ua_blue,"Ua Blue",#03a,0,51,170 +ua_red,"Ua Red",#d9004c,217,0,76 +ube,Ube,#8878c3,136,120,195 +ucla_blue,"Ucla Blue",#536895,83,104,149 +ucla_gold,"Ucla Gold",#ffb300,255,179,0 +ufo_green,"Ufo Green",#3cd070,60,208,112 +ultra_pink,"Ultra Pink",#ff6fff,255,111,255 +ultramarine,Ultramarine,#120a8f,18,10,143 +ultramarine_blue,"Ultramarine Blue",#4166f5,65,102,245 +umber,Umber,#635147,99,81,71 +unbleached_silk,"Unbleached Silk",#ffddca,255,221,202 +united_nations_blue,"United Nations Blue",#5b92e5,91,146,229 +university_of_california_gold,"University Of California Gold",#b78727,183,135,39 +unmellow_yellow,"Unmellow Yellow",#ff6,255,255,102 +up_forest_green,"Up Forest Green",#014421,1,68,33 +up_maroon,"Up Maroon",#7b1113,123,17,19 +upsdell_red,"Upsdell Red",#ae2029,174,32,41 +urobilin,Urobilin,#e1ad21,225,173,33 +usafa_blue,"Usafa Blue",#004f98,0,79,152 +usc_cardinal,"Usc Cardinal",#900,153,0,0 +usc_gold,"Usc Gold",#fc0,255,204,0 +utah_crimson,"Utah Crimson",#d3003f,211,0,63 +vanilla,Vanilla,#f3e5ab,243,229,171 +vegas_gold,"Vegas Gold",#c5b358,197,179,88 +venetian_red,"Venetian Red",#c80815,200,8,21 +verdigris,Verdigris,#43b3ae,67,179,174 +vermilion_cinnabar,"Vermilion (Cinnabar)",#e34234,227,66,52 +vermilion_plochere,"Vermilion (Plochere)",#d9603b,217,96,59 +veronica,Veronica,#a020f0,160,32,240 +violet,Violet,#8f00ff,143,0,255 +violet_blue,Violet-Blue,#324ab2,50,74,178 +violet_color_wheel,"Violet (Color Wheel)",#7f00ff,127,0,255 +violet_ryb,"Violet (Ryb)",#8601af,134,1,175 +violet_web,"Violet (Web)",#ee82ee,238,130,238 +viridian,Viridian,#40826d,64,130,109 +vivid_auburn,"Vivid Auburn",#922724,146,39,36 +vivid_burgundy,"Vivid Burgundy",#9f1d35,159,29,53 +vivid_cerise,"Vivid Cerise",#da1d81,218,29,129 +vivid_tangerine,"Vivid Tangerine",#ffa089,255,160,137 +vivid_violet,"Vivid Violet",#9f00ff,159,0,255 +warm_black,"Warm Black",#004242,0,66,66 +waterspout,Waterspout,#a4f4f9,164,244,249 +wenge,Wenge,#645452,100,84,82 +wheat,Wheat,#f5deb3,245,222,179 +white,White,#fff,255,255,255 +white_smoke,"White Smoke",#f5f5f5,245,245,245 +wild_blue_yonder,"Wild Blue Yonder",#a2add0,162,173,208 +wild_strawberry,"Wild Strawberry",#ff43a4,255,67,164 +wild_watermelon,"Wild Watermelon",#fc6c85,252,108,133 +wine,Wine,#722f37,114,47,55 +wine_dregs,"Wine Dregs",#673147,103,49,71 +wisteria,Wisteria,#c9a0dc,201,160,220 +wood_brown,"Wood Brown",#c19a6b,193,154,107 +xanadu,Xanadu,#738678,115,134,120 +yale_blue,"Yale Blue",#0f4d92,15,77,146 +yellow,Yellow,#ff0,255,255,0 +yellow_green,Yellow-Green,#9acd32,154,205,50 +yellow_munsell,"Yellow (Munsell)",#efcc00,239,204,0 +yellow_ncs,"Yellow (Ncs)",#ffd300,255,211,0 +yellow_orange,"Yellow Orange",#ffae42,255,174,66 +yellow_process,"Yellow (Process)",#ffef00,255,239,0 +yellow_ryb,"Yellow (Ryb)",#fefe33,254,254,51 +zaffre,Zaffre,#0014a8,0,20,168 +zinnwaldite_brown,"Zinnwaldite Brown",#2c1608,44,22,8 diff --git a/skimage/novice/colors.py b/skimage/novice/colors.py new file mode 100644 index 00000000..6ff98a85 --- /dev/null +++ b/skimage/novice/colors.py @@ -0,0 +1,865 @@ +AIR_FORCE_BLUE_RAF = (93, 138, 168) +AIR_FORCE_BLUE_USAF = (0, 48, 143) +AIR_SUPERIORITY_BLUE = (114, 160, 193) +ALABAMA_CRIMSON = (163, 38, 56) +ALICE_BLUE = (240, 248, 255) +ALIZARIN_CRIMSON = (227, 38, 54) +ALLOY_ORANGE = (196, 98, 16) +ALMOND = (239, 222, 205) +AMARANTH = (229, 43, 80) +AMBER = (255, 191, 0) +AMBER_SAE_ECE = (255, 126, 0) +AMERICAN_ROSE = (255, 3, 62) +AMETHYST = (153, 102, 204) +ANDROID_GREEN = (164, 198, 57) +ANTI_FLASH_WHITE = (242, 243, 244) +ANTIQUE_BRASS = (205, 149, 117) +ANTIQUE_FUCHSIA = (145, 92, 131) +ANTIQUE_RUBY = (132, 27, 45) +ANTIQUE_WHITE = (250, 235, 215) +AO_ENGLISH = (0, 128, 0) +APPLE_GREEN = (141, 182, 0) +APRICOT = (251, 206, 177) +AQUA = (0, 255, 255) +AQUAMARINE = (127, 255, 212) +ARMY_GREEN = (75, 83, 32) +ARSENIC = (59, 68, 75) +ARYLIDE_YELLOW = (233, 214, 107) +ASH_GREY = (178, 190, 181) +ASPARAGUS = (135, 169, 107) +ATOMIC_TANGERINE = (255, 153, 102) +AUBURN = (165, 42, 42) +AUREOLIN = (253, 238, 0) +AUROMETALSAURUS = (110, 127, 128) +AVOCADO = (86, 130, 3) +AZURE = (0, 127, 255) +AZURE_MIST_WEB = (240, 255, 255) +BABY_BLUE = (137, 207, 240) +BABY_BLUE_EYES = (161, 202, 241) +BABY_PINK = (244, 194, 194) +BALL_BLUE = (33, 171, 205) +BANANA_MANIA = (250, 231, 181) +BANANA_YELLOW = (255, 225, 53) +BARN_RED = (124, 10, 2) +BATTLESHIP_GREY = (132, 132, 130) +BAZAAR = (152, 119, 123) +BEAU_BLUE = (188, 212, 230) +BEAVER = (159, 129, 112) +BEIGE = (245, 245, 220) +BIG_DIP_O_RUBY = (156, 37, 66) +BISQUE = (255, 228, 196) +BISTRE = (61, 43, 31) +BITTERSWEET = (254, 111, 94) +BITTERSWEET_SHIMMER = (191, 79, 81) +BLACK = (0, 0, 0) +BLACK_BEAN = (61, 12, 2) +BLACK_LEATHER_JACKET = (37, 53, 41) +BLACK_OLIVE = (59, 60, 54) +BLANCHED_ALMOND = (255, 235, 205) +BLAST_OFF_BRONZE = (165, 113, 100) +BLEU_DE_FRANCE = (49, 140, 231) +BLIZZARD_BLUE = (172, 229, 238) +BLOND = (250, 240, 190) +BLUE = (0, 0, 255) +BLUE_BELL = (162, 162, 208) +BLUE_CRAYOLA = (31, 117, 254) +BLUE_GRAY = (102, 153, 204) +BLUE_GREEN = (13, 152, 186) +BLUE_MUNSELL = (0, 147, 175) +BLUE_NCS = (0, 135, 189) +BLUE_PIGMENT = (51, 51, 153) +BLUE_RYB = (2, 71, 254) +BLUE_SAPPHIRE = (18, 97, 128) +BLUE_VIOLET = (138, 43, 226) +BLUSH = (222, 93, 131) +BOLE = (121, 68, 59) +BONDI_BLUE = (0, 149, 182) +BONE = (227, 218, 201) +BOSTON_UNIVERSITY_RED = (204, 0, 0) +BOTTLE_GREEN = (0, 106, 78) +BOYSENBERRY = (135, 50, 96) +BRANDEIS_BLUE = (0, 112, 255) +BRASS = (181, 166, 66) +BRICK_RED = (203, 65, 84) +BRIGHT_CERULEAN = (29, 172, 214) +BRIGHT_GREEN = (102, 255, 0) +BRIGHT_LAVENDER = (191, 148, 228) +BRIGHT_MAROON = (195, 33, 72) +BRIGHT_PINK = (255, 0, 127) +BRIGHT_TURQUOISE = (8, 232, 222) +BRIGHT_UBE = (209, 159, 232) +BRILLIANT_LAVENDER = (244, 187, 255) +BRILLIANT_ROSE = (255, 85, 163) +BRINK_PINK = (251, 96, 127) +BRITISH_RACING_GREEN = (0, 66, 37) +BRONZE = (205, 127, 50) +BROWN_TRADITIONAL = (150, 75, 0) +BROWN_WEB = (165, 42, 42) +BUBBLE_GUM = (255, 193, 204) +BUBBLES = (231, 254, 255) +BUFF = (240, 220, 130) +BULGARIAN_ROSE = (72, 6, 7) +BURGUNDY = (128, 0, 32) +BURLYWOOD = (222, 184, 135) +BURNT_ORANGE = (204, 85, 0) +BURNT_SIENNA = (233, 116, 81) +BURNT_UMBER = (138, 51, 36) +BYZANTINE = (189, 51, 164) +BYZANTIUM = (112, 41, 99) +CADET = (83, 104, 114) +CADET_BLUE = (95, 158, 160) +CADET_GREY = (145, 163, 176) +CADMIUM_GREEN = (0, 107, 60) +CADMIUM_ORANGE = (237, 135, 45) +CADMIUM_RED = (227, 0, 34) +CADMIUM_YELLOW = (255, 246, 0) +CAF_AU_LAIT = (166, 123, 91) +CAF_NOIR = (75, 54, 33) +CAL_POLY_GREEN = (30, 77, 43) +CAMBRIDGE_BLUE = (163, 193, 173) +CAMEL = (193, 154, 107) +CAMEO_PINK = (239, 187, 204) +CAMOUFLAGE_GREEN = (120, 134, 107) +CANARY_YELLOW = (255, 239, 0) +CANDY_APPLE_RED = (255, 8, 0) +CANDY_PINK = (228, 113, 122) +CAPRI = (0, 191, 255) +CAPUT_MORTUUM = (89, 39, 32) +CARDINAL = (196, 30, 58) +CARIBBEAN_GREEN = (0, 204, 153) +CARMINE = (150, 0, 24) +CARMINE_M_P = (215, 0, 64) +CARMINE_PINK = (235, 76, 66) +CARMINE_RED = (255, 0, 56) +CARNATION_PINK = (255, 166, 201) +CARNELIAN = (179, 27, 27) +CAROLINA_BLUE = (153, 186, 221) +CARROT_ORANGE = (237, 145, 33) +CATALINA_BLUE = (6, 42, 120) +CEIL = (146, 161, 207) +CELADON = (172, 225, 175) +CELADON_BLUE = (0, 123, 167) +CELADON_GREEN = (47, 132, 124) +CELESTE_COLOUR = (178, 255, 255) +CELESTIAL_BLUE = (73, 151, 208) +CERISE = (222, 49, 99) +CERISE_PINK = (236, 59, 131) +CERULEAN = (0, 123, 167) +CERULEAN_BLUE = (42, 82, 190) +CERULEAN_FROST = (109, 155, 195) +CG_BLUE = (0, 122, 165) +CG_RED = (224, 60, 49) +CHAMOISEE = (160, 120, 90) +CHAMPAGNE = (250, 214, 165) +CHARCOAL = (54, 69, 79) +CHARM_PINK = (230, 143, 172) +CHARTREUSE_TRADITIONAL = (223, 255, 0) +CHARTREUSE_WEB = (127, 255, 0) +CHERRY = (222, 49, 99) +CHERRY_BLOSSOM_PINK = (255, 183, 197) +CHESTNUT = (205, 92, 92) +CHINA_PINK = (222, 111, 161) +CHINA_ROSE = (168, 81, 110) +CHINESE_RED = (170, 56, 30) +CHOCOLATE_TRADITIONAL = (123, 63, 0) +CHOCOLATE_WEB = (210, 105, 30) +CHROME_YELLOW = (255, 167, 0) +CINEREOUS = (152, 129, 123) +CINNABAR = (227, 66, 52) +CINNAMON = (210, 105, 30) +CITRINE = (228, 208, 10) +CLASSIC_ROSE = (251, 204, 231) +COBALT = (0, 71, 171) +COCOA_BROWN = (210, 105, 30) +COFFEE = (111, 78, 55) +COLUMBIA_BLUE = (155, 221, 255) +CONGO_PINK = (248, 131, 121) +COOL_BLACK = (0, 46, 99) +COOL_GREY = (140, 146, 172) +COPPER = (184, 115, 51) +COPPER_CRAYOLA = (218, 138, 103) +COPPER_PENNY = (173, 111, 105) +COPPER_RED = (203, 109, 81) +COPPER_ROSE = (153, 102, 102) +COQUELICOT = (255, 56, 0) +CORAL = (255, 127, 80) +CORAL_PINK = (248, 131, 121) +CORAL_RED = (255, 64, 64) +CORDOVAN = (137, 63, 69) +CORN = (251, 236, 93) +CORNELL_RED = (179, 27, 27) +CORNFLOWER_BLUE = (100, 149, 237) +CORNSILK = (255, 248, 220) +COSMIC_LATTE = (255, 248, 231) +COTTON_CANDY = (255, 188, 217) +CREAM = (255, 253, 208) +CRIMSON = (220, 20, 60) +CRIMSON_GLORY = (190, 0, 50) +CYAN = (0, 255, 255) +CYAN_PROCESS = (0, 183, 235) +DAFFODIL = (255, 255, 49) +DANDELION = (240, 225, 48) +DARK_BLUE = (0, 0, 139) +DARK_BROWN = (101, 67, 33) +DARK_BYZANTIUM = (93, 57, 84) +DARK_CANDY_APPLE_RED = (164, 0, 0) +DARK_CERULEAN = (8, 69, 126) +DARK_CHESTNUT = (152, 105, 96) +DARK_CORAL = (205, 91, 69) +DARK_CYAN = (0, 139, 139) +DARK_ELECTRIC_BLUE = (83, 104, 120) +DARK_GOLDENROD = (184, 134, 11) +DARK_GRAY = (169, 169, 169) +DARK_GREEN = (1, 50, 32) +DARK_IMPERIAL_BLUE = (0, 65, 106) +DARK_JUNGLE_GREEN = (26, 36, 33) +DARK_KHAKI = (189, 183, 107) +DARK_LAVA = (72, 60, 50) +DARK_LAVENDER = (115, 79, 150) +DARK_MAGENTA = (139, 0, 139) +DARK_MIDNIGHT_BLUE = (0, 51, 102) +DARK_OLIVE_GREEN = (85, 107, 47) +DARK_ORANGE = (255, 140, 0) +DARK_ORCHID = (153, 50, 204) +DARK_PASTEL_BLUE = (119, 158, 203) +DARK_PASTEL_GREEN = (3, 192, 60) +DARK_PASTEL_PURPLE = (150, 111, 214) +DARK_PASTEL_RED = (194, 59, 34) +DARK_PINK = (231, 84, 128) +DARK_POWDER_BLUE = (0, 51, 153) +DARK_RASPBERRY = (135, 38, 87) +DARK_RED = (139, 0, 0) +DARK_SALMON = (233, 150, 122) +DARK_SCARLET = (86, 3, 25) +DARK_SEA_GREEN = (143, 188, 143) +DARK_SIENNA = (60, 20, 20) +DARK_SLATE_BLUE = (72, 61, 139) +DARK_SLATE_GRAY = (47, 79, 79) +DARK_SPRING_GREEN = (23, 114, 69) +DARK_TAN = (145, 129, 81) +DARK_TANGERINE = (255, 168, 18) +DARK_TAUPE = (72, 60, 50) +DARK_TERRA_COTTA = (204, 78, 92) +DARK_TURQUOISE = (0, 206, 209) +DARK_VIOLET = (148, 0, 211) +DARK_YELLOW = (155, 135, 12) +DARTMOUTH_GREEN = (0, 112, 60) +DAVY_S_GREY = (85, 85, 85) +DEBIAN_RED = (215, 10, 83) +DEEP_CARMINE = (169, 32, 62) +DEEP_CARMINE_PINK = (239, 48, 56) +DEEP_CARROT_ORANGE = (233, 105, 44) +DEEP_CERISE = (218, 50, 135) +DEEP_CHAMPAGNE = (250, 214, 165) +DEEP_CHESTNUT = (185, 78, 72) +DEEP_COFFEE = (112, 66, 65) +DEEP_FUCHSIA = (193, 84, 193) +DEEP_JUNGLE_GREEN = (0, 75, 73) +DEEP_LILAC = (153, 85, 187) +DEEP_MAGENTA = (204, 0, 204) +DEEP_PEACH = (255, 203, 164) +DEEP_PINK = (255, 20, 147) +DEEP_RUBY = (132, 63, 91) +DEEP_SAFFRON = (255, 153, 51) +DEEP_SKY_BLUE = (0, 191, 255) +DEEP_TUSCAN_RED = (102, 66, 77) +DENIM = (21, 96, 189) +DESERT = (193, 154, 107) +DESERT_SAND = (237, 201, 175) +DIM_GRAY = (105, 105, 105) +DODGER_BLUE = (30, 144, 255) +DOGWOOD_ROSE = (215, 24, 104) +DOLLAR_BILL = (133, 187, 101) +DRAB = (150, 113, 23) +DUKE_BLUE = (0, 0, 156) +EARTH_YELLOW = (225, 169, 95) +EBONY = (85, 93, 80) +ECRU = (194, 178, 128) +EGGPLANT = (97, 64, 81) +EGGSHELL = (240, 234, 214) +EGYPTIAN_BLUE = (16, 52, 166) +ELECTRIC_BLUE = (125, 249, 255) +ELECTRIC_CRIMSON = (255, 0, 63) +ELECTRIC_CYAN = (0, 255, 255) +ELECTRIC_GREEN = (0, 255, 0) +ELECTRIC_INDIGO = (111, 0, 255) +ELECTRIC_LAVENDER = (244, 187, 255) +ELECTRIC_LIME = (204, 255, 0) +ELECTRIC_PURPLE = (191, 0, 255) +ELECTRIC_ULTRAMARINE = (63, 0, 255) +ELECTRIC_VIOLET = (143, 0, 255) +ELECTRIC_YELLOW = (255, 255, 0) +EMERALD = (80, 200, 120) +ENGLISH_LAVENDER = (180, 131, 149) +ETON_BLUE = (150, 200, 162) +FALLOW = (193, 154, 107) +FALU_RED = (128, 24, 24) +FANDANGO = (181, 51, 137) +FASHION_FUCHSIA = (244, 0, 161) +FAWN = (229, 170, 112) +FELDGRAU = (77, 93, 83) +FERN_GREEN = (79, 121, 66) +FERRARI_RED = (255, 40, 0) +FIELD_DRAB = (108, 84, 30) +FIRE_ENGINE_RED = (206, 32, 41) +FIREBRICK = (178, 34, 34) +FLAME = (226, 88, 34) +FLAMINGO_PINK = (252, 142, 172) +FLAVESCENT = (247, 233, 142) +FLAX = (238, 220, 130) +FLORAL_WHITE = (255, 250, 240) +FLUORESCENT_ORANGE = (255, 191, 0) +FLUORESCENT_PINK = (255, 20, 147) +FLUORESCENT_YELLOW = (204, 255, 0) +FOLLY = (255, 0, 79) +FOREST_GREEN_TRADITIONAL = (1, 68, 33) +FOREST_GREEN_WEB = (34, 139, 34) +FRENCH_BEIGE = (166, 123, 91) +FRENCH_BLUE = (0, 114, 187) +FRENCH_LILAC = (134, 96, 142) +FRENCH_LIME = (204, 255, 0) +FRENCH_RASPBERRY = (199, 44, 72) +FRENCH_ROSE = (246, 74, 138) +FUCHSIA = (255, 0, 255) +FUCHSIA_CRAYOLA = (193, 84, 193) +FUCHSIA_PINK = (255, 119, 255) +FUCHSIA_ROSE = (199, 67, 117) +FULVOUS = (228, 132, 0) +FUZZY_WUZZY = (204, 102, 102) +GAINSBORO = (220, 220, 220) +GAMBOGE = (228, 155, 15) +GHOST_WHITE = (248, 248, 255) +GINGER = (176, 101, 0) +GLAUCOUS = (96, 130, 182) +GLITTER = (230, 232, 250) +GOLD_METALLIC = (212, 175, 55) +GOLD_WEB_GOLDEN = (255, 215, 0) +GOLDEN_BROWN = (153, 101, 21) +GOLDEN_POPPY = (252, 194, 0) +GOLDEN_YELLOW = (255, 223, 0) +GOLDENROD = (218, 165, 32) +GRANNY_SMITH_APPLE = (168, 228, 160) +GRAY = (128, 128, 128) +GRAY_ASPARAGUS = (70, 89, 69) +GRAY_HTML_CSS_GRAY = (128, 128, 128) +GRAY_X11_GRAY = (190, 190, 190) +GREEN = (0, 255, 0) +GREEN_CRAYOLA = (28, 172, 120) +GREEN_HTML_CSS_GREEN = (0, 128, 0) +GREEN_MUNSELL = (0, 168, 119) +GREEN_NCS = (0, 159, 107) +GREEN_PIGMENT = (0, 165, 80) +GREEN_RYB = (102, 176, 50) +GREEN_YELLOW = (173, 255, 47) +GRULLO = (169, 154, 134) +GUPPIE_GREEN = (0, 255, 127) +HALAY_BE = (102, 56, 84) +HAN_BLUE = (68, 108, 207) +HAN_PURPLE = (82, 24, 250) +HANSA_YELLOW = (233, 214, 107) +HARLEQUIN = (63, 255, 0) +HARVARD_CRIMSON = (201, 0, 22) +HARVEST_GOLD = (218, 145, 0) +HEART_GOLD = (128, 128, 0) +HELIOTROPE = (223, 115, 255) +HOLLYWOOD_CERISE = (244, 0, 161) +HONEYDEW = (240, 255, 240) +HONOLULU_BLUE = (0, 127, 191) +HOOKER_S_GREEN = (73, 121, 107) +HOT_MAGENTA = (255, 29, 206) +HOT_PINK = (255, 105, 180) +HUNTER_GREEN = (53, 94, 59) +ICEBERG = (113, 166, 210) +ICTERINE = (252, 247, 94) +IMPERIAL_BLUE = (0, 35, 149) +INCHWORM = (178, 236, 93) +INDIA_GREEN = (19, 136, 8) +INDIAN_RED = (205, 92, 92) +INDIAN_YELLOW = (227, 168, 87) +INDIGO = (111, 0, 255) +INDIGO_DYE = (0, 65, 106) +INDIGO_WEB = (75, 0, 130) +INTERNATIONAL_KLEIN_BLUE = (0, 47, 167) +INTERNATIONAL_ORANGE_AEROSPACE = (255, 79, 0) +INTERNATIONAL_ORANGE_ENGINEERING = (186, 22, 12) +INTERNATIONAL_ORANGE_GOLDEN_GATE_BRIDGE = (192, 54, 44) +IRIS = (90, 79, 207) +ISABELLINE = (244, 240, 236) +ISLAMIC_GREEN = (0, 144, 0) +IVORY = (255, 255, 240) +JADE = (0, 168, 107) +JASMINE = (248, 222, 126) +JASPER = (215, 59, 62) +JAZZBERRY_JAM = (165, 11, 94) +JET = (52, 52, 52) +JONQUIL = (250, 218, 94) +JUNE_BUD = (189, 218, 87) +JUNGLE_GREEN = (41, 171, 135) +KELLY_GREEN = (76, 187, 23) +KENYAN_COPPER = (124, 28, 5) +KHAKI_HTML_CSS_KHAKI = (195, 176, 145) +KHAKI_X11_LIGHT_KHAKI = (240, 230, 140) +KU_CRIMSON = (232, 0, 13) +LA_SALLE_GREEN = (8, 120, 48) +LANGUID_LAVENDER = (214, 202, 221) +LAPIS_LAZULI = (38, 97, 156) +LASER_LEMON = (254, 254, 34) +LAUREL_GREEN = (169, 186, 157) +LAVA = (207, 16, 32) +LAVENDER_BLUE = (204, 204, 255) +LAVENDER_BLUSH = (255, 240, 245) +LAVENDER_FLORAL = (181, 126, 220) +LAVENDER_GRAY = (196, 195, 208) +LAVENDER_INDIGO = (148, 87, 235) +LAVENDER_MAGENTA = (238, 130, 238) +LAVENDER_MIST = (230, 230, 250) +LAVENDER_PINK = (251, 174, 210) +LAVENDER_PURPLE = (150, 123, 182) +LAVENDER_ROSE = (251, 160, 227) +LAVENDER_WEB = (230, 230, 250) +LAWN_GREEN = (124, 252, 0) +LEMON = (255, 247, 0) +LEMON_CHIFFON = (255, 250, 205) +LEMON_LIME = (227, 255, 0) +LICORICE = (26, 17, 16) +LIGHT_APRICOT = (253, 213, 177) +LIGHT_BLUE = (173, 216, 230) +LIGHT_BROWN = (181, 101, 29) +LIGHT_CARMINE_PINK = (230, 103, 113) +LIGHT_CORAL = (240, 128, 128) +LIGHT_CORNFLOWER_BLUE = (147, 204, 234) +LIGHT_CRIMSON = (245, 105, 145) +LIGHT_CYAN = (224, 255, 255) +LIGHT_FUCHSIA_PINK = (249, 132, 239) +LIGHT_GOLDENROD_YELLOW = (250, 250, 210) +LIGHT_GRAY = (211, 211, 211) +LIGHT_GREEN = (144, 238, 144) +LIGHT_KHAKI = (240, 230, 140) +LIGHT_PASTEL_PURPLE = (177, 156, 217) +LIGHT_PINK = (255, 182, 193) +LIGHT_RED_OCHRE = (233, 116, 81) +LIGHT_SALMON = (255, 160, 122) +LIGHT_SALMON_PINK = (255, 153, 153) +LIGHT_SEA_GREEN = (32, 178, 170) +LIGHT_SKY_BLUE = (135, 206, 250) +LIGHT_SLATE_GRAY = (119, 136, 153) +LIGHT_TAUPE = (179, 139, 109) +LIGHT_THULIAN_PINK = (230, 143, 172) +LIGHT_YELLOW = (255, 255, 224) +LILAC = (200, 162, 200) +LIME = (191, 255, 0) +LIME_GREEN = (50, 205, 50) +LIME_WEB_X11_GREEN = (0, 255, 0) +LIMERICK = (157, 194, 9) +LINCOLN_GREEN = (25, 89, 5) +LINEN = (250, 240, 230) +LION = (193, 154, 107) +LITTLE_BOY_BLUE = (108, 160, 220) +LIVER = (83, 75, 79) +LUST = (230, 32, 32) +MAGENTA = (255, 0, 255) +MAGENTA_DYE = (202, 31, 123) +MAGENTA_PROCESS = (255, 0, 144) +MAGIC_MINT = (170, 240, 209) +MAGNOLIA = (248, 244, 255) +MAHOGANY = (192, 64, 0) +MAIZE = (251, 236, 93) +MAJORELLE_BLUE = (96, 80, 220) +MALACHITE = (11, 218, 81) +MANATEE = (151, 154, 170) +MANGO_TANGO = (255, 130, 67) +MANTIS = (116, 195, 101) +MARDI_GRAS = (136, 0, 133) +MAROON_CRAYOLA = (195, 33, 72) +MAROON_HTML_CSS = (128, 0, 0) +MAROON_X11 = (176, 48, 96) +MAUVE = (224, 176, 255) +MAUVE_TAUPE = (145, 95, 109) +MAUVELOUS = (239, 152, 170) +MAYA_BLUE = (115, 194, 251) +MEAT_BROWN = (229, 183, 59) +MEDIUM_AQUAMARINE = (102, 221, 170) +MEDIUM_BLUE = (0, 0, 205) +MEDIUM_CANDY_APPLE_RED = (226, 6, 44) +MEDIUM_CARMINE = (175, 64, 53) +MEDIUM_CHAMPAGNE = (243, 229, 171) +MEDIUM_ELECTRIC_BLUE = (3, 80, 150) +MEDIUM_JUNGLE_GREEN = (28, 53, 45) +MEDIUM_LAVENDER_MAGENTA = (221, 160, 221) +MEDIUM_ORCHID = (186, 85, 211) +MEDIUM_PERSIAN_BLUE = (0, 103, 165) +MEDIUM_PURPLE = (147, 112, 219) +MEDIUM_RED_VIOLET = (187, 51, 133) +MEDIUM_RUBY = (170, 64, 105) +MEDIUM_SEA_GREEN = (60, 179, 113) +MEDIUM_SLATE_BLUE = (123, 104, 238) +MEDIUM_SPRING_BUD = (201, 220, 135) +MEDIUM_SPRING_GREEN = (0, 250, 154) +MEDIUM_TAUPE = (103, 76, 71) +MEDIUM_TURQUOISE = (72, 209, 204) +MEDIUM_TUSCAN_RED = (121, 68, 59) +MEDIUM_VERMILION = (217, 96, 59) +MEDIUM_VIOLET_RED = (199, 21, 133) +MELLOW_APRICOT = (248, 184, 120) +MELLOW_YELLOW = (248, 222, 126) +MELON = (253, 188, 180) +MIDNIGHT_BLUE = (25, 25, 112) +MIDNIGHT_GREEN_EAGLE_GREEN = (0, 73, 83) +MIKADO_YELLOW = (255, 196, 12) +MINT = (62, 180, 137) +MINT_CREAM = (245, 255, 250) +MINT_GREEN = (152, 255, 152) +MISTY_ROSE = (255, 228, 225) +MOCCASIN = (250, 235, 215) +MODE_BEIGE = (150, 113, 23) +MOONSTONE_BLUE = (115, 169, 194) +MORDANT_RED_19 = (174, 12, 0) +MOSS_GREEN = (173, 223, 173) +MOUNTAIN_MEADOW = (48, 186, 143) +MOUNTBATTEN_PINK = (153, 122, 141) +MSU_GREEN = (24, 69, 59) +MULBERRY = (197, 75, 140) +MUSTARD = (255, 219, 88) +MYRTLE = (33, 66, 30) +NADESHIKO_PINK = (246, 173, 198) +NAPIER_GREEN = (42, 128, 0) +NAPLES_YELLOW = (250, 218, 94) +NAVAJO_WHITE = (255, 222, 173) +NAVY_BLUE = (0, 0, 128) +NEON_CARROT = (255, 163, 67) +NEON_FUCHSIA = (254, 65, 100) +NEON_GREEN = (57, 255, 20) +NEW_YORK_PINK = (215, 131, 127) +NON_PHOTO_BLUE = (164, 221, 237) +NORTH_TEXAS_GREEN = (5, 144, 51) +OCEAN_BOAT_BLUE = (0, 119, 190) +OCHRE = (204, 119, 34) +OFFICE_GREEN = (0, 128, 0) +OLD_GOLD = (207, 181, 59) +OLD_LACE = (253, 245, 230) +OLD_LAVENDER = (121, 104, 120) +OLD_MAUVE = (103, 49, 71) +OLD_ROSE = (192, 128, 129) +OLIVE = (128, 128, 0) +OLIVE_DRAB_7 = (60, 52, 31) +OLIVE_DRAB_WEB_OLIVE_DRAB_3 = (107, 142, 35) +OLIVINE = (154, 185, 115) +ONYX = (53, 56, 57) +OPERA_MAUVE = (183, 132, 167) +ORANGE = (255, 127, 0) +ORANGE_PEEL = (255, 159, 0) +ORANGE_RED = (255, 69, 0) +ORANGE_RYB = (251, 153, 2) +ORANGE_WEB_COLOR = (255, 165, 0) +ORCHID = (218, 112, 214) +OTTER_BROWN = (101, 67, 33) +OU_CRIMSON_RED = (153, 0, 0) +OUTER_SPACE = (65, 74, 76) +OUTRAGEOUS_ORANGE = (255, 110, 74) +OXFORD_BLUE = (0, 33, 71) +PAKISTAN_GREEN = (0, 102, 0) +PALATINATE_BLUE = (39, 59, 226) +PALATINATE_PURPLE = (104, 40, 96) +PALE_AQUA = (188, 212, 230) +PALE_BLUE = (175, 238, 238) +PALE_BROWN = (152, 118, 84) +PALE_CARMINE = (175, 64, 53) +PALE_CERULEAN = (155, 196, 226) +PALE_CHESTNUT = (221, 173, 175) +PALE_COPPER = (218, 138, 103) +PALE_CORNFLOWER_BLUE = (171, 205, 239) +PALE_GOLD = (230, 190, 138) +PALE_GOLDENROD = (238, 232, 170) +PALE_GREEN = (152, 251, 152) +PALE_LAVENDER = (220, 208, 255) +PALE_MAGENTA = (249, 132, 229) +PALE_PINK = (250, 218, 221) +PALE_PLUM = (221, 160, 221) +PALE_RED_VIOLET = (219, 112, 147) +PALE_ROBIN_EGG_BLUE = (150, 222, 209) +PALE_SILVER = (201, 192, 187) +PALE_SPRING_BUD = (236, 235, 189) +PALE_TAUPE = (188, 152, 126) +PALE_VIOLET_RED = (219, 112, 147) +PANSY_PURPLE = (120, 24, 74) +PAPAYA_WHIP = (255, 239, 213) +PARIS_GREEN = (80, 200, 120) +PASTEL_BLUE = (174, 198, 207) +PASTEL_BROWN = (131, 105, 83) +PASTEL_GRAY = (207, 207, 196) +PASTEL_GREEN = (119, 221, 119) +PASTEL_MAGENTA = (244, 154, 194) +PASTEL_ORANGE = (255, 179, 71) +PASTEL_PINK = (222, 165, 164) +PASTEL_PURPLE = (179, 158, 181) +PASTEL_RED = (255, 105, 97) +PASTEL_VIOLET = (203, 153, 201) +PASTEL_YELLOW = (253, 253, 150) +PATRIARCH = (128, 0, 128) +PAYNE_S_GREY = (83, 104, 120) +PEACH = (255, 229, 180) +PEACH_CRAYOLA = (255, 203, 164) +PEACH_ORANGE = (255, 204, 153) +PEACH_PUFF = (255, 218, 185) +PEACH_YELLOW = (250, 223, 173) +PEAR = (209, 226, 49) +PEARL = (234, 224, 200) +PEARL_AQUA = (136, 216, 192) +PEARLY_PURPLE = (183, 104, 162) +PERIDOT = (230, 226, 0) +PERIWINKLE = (204, 204, 255) +PERSIAN_BLUE = (28, 57, 187) +PERSIAN_GREEN = (0, 166, 147) +PERSIAN_INDIGO = (50, 18, 122) +PERSIAN_ORANGE = (217, 144, 88) +PERSIAN_PINK = (247, 127, 190) +PERSIAN_PLUM = (112, 28, 28) +PERSIAN_RED = (204, 51, 51) +PERSIAN_ROSE = (254, 40, 162) +PERSIMMON = (236, 88, 0) +PERU = (205, 133, 63) +PHLOX = (223, 0, 255) +PHTHALO_BLUE = (0, 15, 137) +PHTHALO_GREEN = (18, 53, 36) +PIGGY_PINK = (253, 221, 230) +PINE_GREEN = (1, 121, 111) +PINK = (255, 192, 203) +PINK_LACE = (255, 221, 244) +PINK_ORANGE = (255, 153, 102) +PINK_PEARL = (231, 172, 207) +PINK_SHERBET = (247, 143, 167) +PISTACHIO = (147, 197, 114) +PLATINUM = (229, 228, 226) +PLUM_TRADITIONAL = (142, 69, 133) +PLUM_WEB = (221, 160, 221) +PORTLAND_ORANGE = (255, 90, 54) +POWDER_BLUE_WEB = (176, 224, 230) +PRINCETON_ORANGE = (255, 143, 0) +PRUNE = (112, 28, 28) +PRUSSIAN_BLUE = (0, 49, 83) +PSYCHEDELIC_PURPLE = (223, 0, 255) +PUCE = (204, 136, 153) +PUMPKIN = (255, 117, 24) +PURPLE_HEART = (105, 53, 156) +PURPLE_HTML_CSS = (128, 0, 128) +PURPLE_MOUNTAIN_MAJESTY = (150, 120, 182) +PURPLE_MUNSELL = (159, 0, 197) +PURPLE_PIZZAZZ = (254, 78, 218) +PURPLE_TAUPE = (80, 64, 77) +PURPLE_X11 = (160, 32, 240) +QUARTZ = (81, 72, 79) +RACKLEY = (93, 138, 168) +RADICAL_RED = (255, 53, 94) +RAJAH = (251, 171, 96) +RASPBERRY = (227, 11, 93) +RASPBERRY_GLACE = (145, 95, 109) +RASPBERRY_PINK = (226, 80, 152) +RASPBERRY_ROSE = (179, 68, 108) +RAW_UMBER = (130, 102, 68) +RAZZLE_DAZZLE_ROSE = (255, 51, 204) +RAZZMATAZZ = (227, 37, 107) +RED = (255, 0, 0) +RED_BROWN = (165, 42, 42) +RED_DEVIL = (134, 1, 17) +RED_MUNSELL = (242, 0, 60) +RED_NCS = (196, 2, 51) +RED_ORANGE = (255, 83, 73) +RED_PIGMENT = (237, 28, 36) +RED_RYB = (254, 39, 18) +RED_VIOLET = (199, 21, 133) +REDWOOD = (171, 78, 82) +REGALIA = (82, 45, 128) +RESOLUTION_BLUE = (0, 35, 135) +RICH_BLACK = (0, 64, 64) +RICH_BRILLIANT_LAVENDER = (241, 167, 254) +RICH_CARMINE = (215, 0, 64) +RICH_ELECTRIC_BLUE = (8, 146, 208) +RICH_LAVENDER = (167, 107, 207) +RICH_LILAC = (182, 102, 210) +RICH_MAROON = (176, 48, 96) +RIFLE_GREEN = (65, 72, 51) +ROBIN_EGG_BLUE = (0, 204, 204) +ROSE = (255, 0, 127) +ROSE_BONBON = (249, 66, 158) +ROSE_EBONY = (103, 72, 70) +ROSE_GOLD = (183, 110, 121) +ROSE_MADDER = (227, 38, 54) +ROSE_PINK = (255, 102, 204) +ROSE_QUARTZ = (170, 152, 169) +ROSE_TAUPE = (144, 93, 93) +ROSE_VALE = (171, 78, 82) +ROSEWOOD = (101, 0, 11) +ROSSO_CORSA = (212, 0, 0) +ROSY_BROWN = (188, 143, 143) +ROYAL_AZURE = (0, 56, 168) +ROYAL_BLUE_TRADITIONAL = (0, 35, 102) +ROYAL_BLUE_WEB = (65, 105, 225) +ROYAL_FUCHSIA = (202, 44, 146) +ROYAL_PURPLE = (120, 81, 169) +ROYAL_YELLOW = (250, 218, 94) +RUBINE_RED = (209, 0, 86) +RUBY = (224, 17, 95) +RUBY_RED = (155, 17, 30) +RUDDY = (255, 0, 40) +RUDDY_BROWN = (187, 101, 40) +RUDDY_PINK = (225, 142, 150) +RUFOUS = (168, 28, 7) +RUSSET = (128, 70, 27) +RUST = (183, 65, 14) +RUSTY_RED = (218, 44, 67) +SACRAMENTO_STATE_GREEN = (0, 86, 63) +SADDLE_BROWN = (139, 69, 19) +SAFETY_ORANGE_BLAZE_ORANGE = (255, 103, 0) +SAFFRON = (244, 196, 48) +SALMON = (255, 140, 105) +SALMON_PINK = (255, 145, 164) +SAND = (194, 178, 128) +SAND_DUNE = (150, 113, 23) +SANDSTORM = (236, 213, 64) +SANDY_BROWN = (244, 164, 96) +SANDY_TAUPE = (150, 113, 23) +SANGRIA = (146, 0, 10) +SAP_GREEN = (80, 125, 42) +SAPPHIRE = (15, 82, 186) +SAPPHIRE_BLUE = (0, 103, 165) +SATIN_SHEEN_GOLD = (203, 161, 53) +SCARLET = (255, 36, 0) +SCARLET_CRAYOLA = (253, 14, 53) +SCHOOL_BUS_YELLOW = (255, 216, 0) +SCREAMIN_GREEN = (118, 255, 122) +SEA_BLUE = (0, 105, 148) +SEA_GREEN = (46, 139, 87) +SEAL_BROWN = (50, 20, 20) +SEASHELL = (255, 245, 238) +SELECTIVE_YELLOW = (255, 186, 0) +SEPIA = (112, 66, 20) +SHADOW = (138, 121, 93) +SHAMROCK_GREEN = (0, 158, 96) +SHOCKING_PINK = (252, 15, 192) +SHOCKING_PINK_CRAYOLA = (255, 111, 255) +SIENNA = (136, 45, 23) +SILVER = (192, 192, 192) +SINOPIA = (203, 65, 11) +SKOBELOFF = (0, 116, 116) +SKY_BLUE = (135, 206, 235) +SKY_MAGENTA = (207, 113, 175) +SLATE_BLUE = (106, 90, 205) +SLATE_GRAY = (112, 128, 144) +SMALT_DARK_POWDER_BLUE = (0, 51, 153) +SMOKEY_TOPAZ = (147, 61, 65) +SMOKY_BLACK = (16, 12, 8) +SNOW = (255, 250, 250) +SPIRO_DISCO_BALL = (15, 192, 252) +SPRING_BUD = (167, 252, 0) +SPRING_GREEN = (0, 255, 127) +ST_PATRICK_S_BLUE = (35, 41, 122) +STEEL_BLUE = (70, 130, 180) +STIL_DE_GRAIN_YELLOW = (250, 218, 94) +STIZZA = (153, 0, 0) +STORMCLOUD = (79, 102, 106) +STRAW = (228, 217, 111) +SUNGLOW = (255, 204, 51) +SUNSET = (250, 214, 165) +TAN = (210, 180, 140) +TANGELO = (249, 77, 0) +TANGERINE = (242, 133, 0) +TANGERINE_YELLOW = (255, 204, 0) +TANGO_PINK = (228, 113, 122) +TAUPE = (72, 60, 50) +TAUPE_GRAY = (139, 133, 137) +TEA_GREEN = (208, 240, 192) +TEA_ROSE_ORANGE = (248, 131, 121) +TEA_ROSE_ROSE = (244, 194, 194) +TEAL = (0, 128, 128) +TEAL_BLUE = (54, 117, 136) +TEAL_GREEN = (0, 130, 127) +TELEMAGENTA = (207, 52, 118) +TENN_TAWNY = (205, 87, 0) +TERRA_COTTA = (226, 114, 91) +THISTLE = (216, 191, 216) +THULIAN_PINK = (222, 111, 161) +TICKLE_ME_PINK = (252, 137, 172) +TIFFANY_BLUE = (10, 186, 181) +TIGER_S_EYE = (224, 141, 60) +TIMBERWOLF = (219, 215, 210) +TITANIUM_YELLOW = (238, 230, 0) +TOMATO = (255, 99, 71) +TOOLBOX = (116, 108, 192) +TOPAZ = (255, 200, 124) +TRACTOR_RED = (253, 14, 53) +TROLLEY_GREY = (128, 128, 128) +TROPICAL_RAIN_FOREST = (0, 117, 94) +TRUE_BLUE = (0, 115, 207) +TUFTS_BLUE = (65, 125, 193) +TUMBLEWEED = (222, 170, 136) +TURKISH_ROSE = (181, 114, 129) +TURQUOISE = (48, 213, 200) +TURQUOISE_BLUE = (0, 255, 239) +TURQUOISE_GREEN = (160, 214, 180) +TUSCAN_RED = (124, 72, 72) +TWILIGHT_LAVENDER = (138, 73, 107) +TYRIAN_PURPLE = (102, 2, 60) +UA_BLUE = (0, 51, 170) +UA_RED = (217, 0, 76) +UBE = (136, 120, 195) +UCLA_BLUE = (83, 104, 149) +UCLA_GOLD = (255, 179, 0) +UFO_GREEN = (60, 208, 112) +ULTRA_PINK = (255, 111, 255) +ULTRAMARINE = (18, 10, 143) +ULTRAMARINE_BLUE = (65, 102, 245) +UMBER = (99, 81, 71) +UNBLEACHED_SILK = (255, 221, 202) +UNITED_NATIONS_BLUE = (91, 146, 229) +UNIVERSITY_OF_CALIFORNIA_GOLD = (183, 135, 39) +UNMELLOW_YELLOW = (255, 255, 102) +UP_FOREST_GREEN = (1, 68, 33) +UP_MAROON = (123, 17, 19) +UPSDELL_RED = (174, 32, 41) +UROBILIN = (225, 173, 33) +USAFA_BLUE = (0, 79, 152) +USC_CARDINAL = (153, 0, 0) +USC_GOLD = (255, 204, 0) +UTAH_CRIMSON = (211, 0, 63) +VANILLA = (243, 229, 171) +VEGAS_GOLD = (197, 179, 88) +VENETIAN_RED = (200, 8, 21) +VERDIGRIS = (67, 179, 174) +VERMILION_CINNABAR = (227, 66, 52) +VERMILION_PLOCHERE = (217, 96, 59) +VERONICA = (160, 32, 240) +VIOLET = (143, 0, 255) +VIOLET_BLUE = (50, 74, 178) +VIOLET_COLOR_WHEEL = (127, 0, 255) +VIOLET_RYB = (134, 1, 175) +VIOLET_WEB = (238, 130, 238) +VIRIDIAN = (64, 130, 109) +VIVID_AUBURN = (146, 39, 36) +VIVID_BURGUNDY = (159, 29, 53) +VIVID_CERISE = (218, 29, 129) +VIVID_TANGERINE = (255, 160, 137) +VIVID_VIOLET = (159, 0, 255) +WARM_BLACK = (0, 66, 66) +WATERSPOUT = (164, 244, 249) +WENGE = (100, 84, 82) +WHEAT = (245, 222, 179) +WHITE = (255, 255, 255) +WHITE_SMOKE = (245, 245, 245) +WILD_BLUE_YONDER = (162, 173, 208) +WILD_STRAWBERRY = (255, 67, 164) +WILD_WATERMELON = (252, 108, 133) +WINE = (114, 47, 55) +WINE_DREGS = (103, 49, 71) +WISTERIA = (201, 160, 220) +WOOD_BROWN = (193, 154, 107) +XANADU = (115, 134, 120) +YALE_BLUE = (15, 77, 146) +YELLOW = (255, 255, 0) +YELLOW_GREEN = (154, 205, 50) +YELLOW_MUNSELL = (239, 204, 0) +YELLOW_NCS = (255, 211, 0) +YELLOW_ORANGE = (255, 174, 66) +YELLOW_PROCESS = (255, 239, 0) +YELLOW_RYB = (254, 254, 51) +ZAFFRE = (0, 20, 168) +ZINNWALDITE_BROWN = (44, 22, 8) diff --git a/skimage/novice/make_colors.py b/skimage/novice/make_colors.py new file mode 100644 index 00000000..2c14063d --- /dev/null +++ b/skimage/novice/make_colors.py @@ -0,0 +1,60 @@ +#!/usr/bin/python +import argparse, csv + +# Imports color names from a CSV file (colors.csv) and outputs a Python file +# with color name definitions (colors.py). + +def download_colors(path): + import urllib2, re + from bs4 import BeautifulSoup + + # All colors seem to be on this page + url = "http://en.wikipedia.org/wiki/List_of_colors:_A-M" + request = urllib2.Request(url) + opener = urllib2.build_opener() + request.add_header("User-Agent", "Mozilla/5.0") + html = opener.open(request).read() + + # Find first table with "Color names" caption + soup = BeautifulSoup(html, "lxml") + color_table = [t for t in soup.findAll("table") if t.find("caption") is not None + and t.find("caption").string == "Color names"][0] + + with open(path, "w") as out_file: + writer = csv.writer(out_file) + + # Each table row has the color name in a th and the hex + # color in the second td cell. + for row in color_table.findAll("tr"): + th = row.find("th") + cells = row.findAll("td") + if th is None or len(cells) < 2: + continue + + name = th.string.encode("ascii", "ignore") + + # Strip parens and replace non-alphanumeric characters with underscores + id_name = re.sub("[^a-zA-Z0-9]", "_", name.lower().replace("(", "").replace(")", "")) + hex_str = cells[1].string.encode("ascii", "ignore") + r, g, b = (int(hex_str[1:3], 16), int(hex_str[3:5], 16), int(hex_str[5:7], 16)) + + writer.writerow((id_name, name, hex_str, str(r), str(g), str(b))) + +# -------------------------------------------------- + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--input", "-i", type=str, default="colors.csv", help="Input file (CSV)") + parser.add_argument("--output", "-o", type=str, default="colors.py", help="Output file (Python)") + parser.add_argument("--download", "-d", action="store_true", help="Download from Wikipedia") + args = parser.parse_args() + + if args.download: + download_colors(args.input) + + with open(args.input, "r") as input_file: + with open(args.output, "w") as output_file: + for row in csv.reader(input_file): + name = row[0].upper() + rgb = (int(row[-3]), int(row[-2]), int(row[-1])) + output_file.write("{0} = {1}\n".format(name, rgb)) diff --git a/skimage/novice/novice.py b/skimage/novice/novice.py new file mode 100644 index 00000000..0744afc5 --- /dev/null +++ b/skimage/novice/novice.py @@ -0,0 +1,778 @@ +import os, numpy as np, imghdr +from skimage.util import img_as_ubyte +import skimage.io, skimage.transform + +# ================================================== + +class Pixel(object): + """A single pixel in a Picture. + + Attributes + ---------- + pic : Picture + The Picture object that this pixel references. + image : array_like + Byte array with raw image data (RGB). + x : int + Horizontal coordinate of this pixel (left = 0). + y : int + Vertical coordinate of this pixel (bottom = 0). + rgb : tuple + RGB tuple with red, green, and blue components (0-255) + + """ + def __init__(self, pic, image, x, y, rgb): + self._picture = pic + self._image = image + self._x = x + self._y = y + self._red = self._validate(rgb[0]) + self._green = self._validate(rgb[1]) + self._blue = self._validate(rgb[2]) + + @property + def x(self): + """Gets the horizontal location (left = 0). + + Returns + ------- + x : int + The horizontal location of the pixel. + + """ + return self._x + + @property + def y(self): + """Gets the vertical location (bottom = 0). + + Returns + ------- + y : int + The vertical location of the pixel. + + """ + return self._y + + @property + def red(self): + """Gets the red component of the pixel. + + Returns + ------- + value : int + The red component of the pixel (0-255). + """ + return self._red + + @red.setter + def red(self, value): + """Sets the red component of the pixel. + + Parameters + ---------- + value : int + Red component of the pixel (0-255) + + """ + self._red = self._validate(value) + self._setpixel() + + @property + def green(self): + """Gets the green component of the pixel. + + Returns + ------- + value : int + The green component of the pixel (0-255). + """ + return self._green + + @green.setter + def green(self, value): + """Sets the green component of the pixel. + + Parameters + ---------- + value : int + Green component of the pixel (0-255) + + """ + self._green = self._validate(value) + self._setpixel() + + @property + def blue(self): + """Gets the blue component of the pixel. + + Returns + ------- + value : int + The blue component of the pixel (0-255). + """ + return self._blue + + @blue.setter + def blue(self, value): + """Sets the blue component of the pixel. + + Parameters + ---------- + value : int + Blue component of the pixel (0-255) + + """ + self._blue = self._validate(value) + self._setpixel() + + @property + def rgb(self): + """Gets the RGB color of the pixel. + + Returns + ---------- + color : tuple + RGB tuple with red, green, and blue components (0-255) + + """ + return (self.red, self.green, self.blue) + + @rgb.setter + def rgb(self, value): + """Sets the RGB color of the pixel. + + Parameters + ---------- + value : tuple + RGB tuple with red, green, and blue components (0-255) + + """ + for v in value: + self._validate(v) + + self._red = value[0] + self._green = value[1] + self._blue = value[2] + self._setpixel() + + def _validate(self, value): + """Verifies that the pixel value is in [0, 255]. + + """ + try: + value = int(value) + if (value < 0) or (value > 255): + raise ValueError() + except ValueError: + raise ValueError("Expected an integer between 0 and 255, but got {0} instead!".format(value)) + + return value + + def _setpixel(self): + """Sets the actual pixel value in the picture. + NOTE: Using Cartesian coordinate system! + + """ + # skimage dimensions are flipped: y, x + self._image[self._picture.height - self._y - 1, self._x] = \ + (self.red, self.green, self.blue) + + # Modified pictures lose their paths + self._picture._picture_path = None + self._picture._picture_modified = True + + def __repr__(self): + return "Pixel (red: {0}, green: {1}, blue: {2})".format(self.red, self.green, self.blue) + +# ================================================== + +class PixelGroup(object): + """A group of Pixel objects that can be manipulated together. + + Attributes + ---------- + pic : Picture + The Picture object that this pixel group references. + key : tuple + tuple with x and y slices or ints for extracting part of raw image data. + + """ + def __init__(self, pic, key): + self._pic = pic + + # Use a slice so that the _getdim and _setdim functions can index + # consistently. + if isinstance(key[0], int): + key = (slice(key[0], key[0] + 1), key[1]) + + if isinstance(key[1], int): + key = (key[0], slice(key[1], key[1] + 1)) + + for dim_slice in key: + if dim_slice.start is not None and dim_slice.start < 0: + raise IndexError("Negative slicing not supported") + + if dim_slice.stop is not None and dim_slice.stop < 0: + raise IndexError("Negative slicing not supported") + + if dim_slice.step is not None and dim_slice.step != 1: + raise IndexError("Only a step size of 1 is supported") + + # =========== + # Flip y axis + # =========== + y_slice = key[1] + start = y_slice.start if y_slice.start is not None else 0 + stop = y_slice.stop if y_slice.stop is not None else pic.height + + start = pic.height - start - 1 + stop = pic.height - stop + + key = (key[0], slice(stop, start + 1, y_slice.step)) + + # skimage dimensions are flipped: y, x + self._key = (key[1], key[0]) + self._image = pic._image + + # Save slice for _getdim operations. + # This allows you to swap parts of an image. + self._slice = self._image[self._key[0], self._key[1]] + + shape = self._getdim(0).shape + self.size = (shape[1], shape[0]) + + def _getdim(self, dim): + """Gets a specific dimension out of the raw image data slice. + + """ + return self._slice[:, :, dim] + + def _setdim(self, dim, value): + """ Sets a specific dimension in the raw image data slice. + + """ + self._image[self._key[0], self._key[1], dim] = value + + @property + def red(self): + """Gets the red component of the pixel. + + Returns + ------- + value : int + The red component of the pixel (0-255). + """ + return self._getdim(0).ravel() + + @red.setter + def red(self, value): + """Sets the red component of the pixel. + + Parameters + ---------- + value : int + Red component of the pixel (0-255) + + """ + self._setdim(0, value) + + @property + def green(self): + """Gets the green component of the pixel. + + Returns + ------- + value : int + The green component of the pixel (0-255). + """ + return self._getdim(1).ravel() + + @green.setter + def green(self, value): + """Sets the green component of the pixel. + + Parameters + ---------- + value : int + green component of the pixel (0-255) + + """ + self._setdim(1, value) + + @property + def blue(self): + """Gets the blue component of the pixel. + + Returns + ------- + value : int + The blue component of the pixel (0-255). + """ + return self._getdim(2).ravel() + + @blue.setter + def blue(self, value): + """Sets the blue component of the pixel. + + Parameters + ---------- + value : int + blue component of the pixel (0-255) + + """ + self._setdim(2, value) + + @property + def rgb(self): + """Gets the RGB color of the pixel. + + Returns + ---------- + color : tuple + RGB tuple with red, green, and blue components (0-255) + + """ + return self._getdim(None) + + @rgb.setter + def rgb(self, value): + """Sets the RGB color of the pixel. + + Parameters + ---------- + value : tuple + RGB tuple with red, green, and blue components (0-255) + + """ + self._setdim(None, value) + + def __iter__(self): + """Iterates through all pixels in the pixel group. + + """ + x_idx = range(self._pic.width)[self._key[0]] + y_idx = range(self._pic.height)[self._key[1]] + + for x in x_idx: + for y in y_idx: + yield self._pic._makepixel((x, y)) + + def __repr__(self): + return "PixelGroup ({0} pixels)".format(self.size[0] * self.size[1]) + +# ================================================== + +class Picture(object): + """A 2-D picture made up of pixels. + + Attributes + ---------- + path : str + Path to an image file to load. + size : tuple + Size of the empty image to create (width, height). + color : tuple + Color to fill empty image if size is given (red, green, blue) [0-255]. + image : array_like + Raw RGB image data [0-255] + + Notes + ----- + Cannot provide more than one of 'path' and 'size' and 'image'. + Can only provide 'color' if 'size' provided. + + Examples + -------- + Load an image from a file + + >>> pic = Picture(path="/path/to/image/file.png") + + Create a blank 100 pixel wide, 200 pixel tall white image + + >>> pic = Picture(size=(100, 200), color=(255, 255, 255)) + + Use numpy to make an RGB byte array (shape is height x width x 3) + + >>> import numpy as np + >>> data = np.zeros(shape=(200, 100, 3), dtype=np.int8) + >>> data[:, :, 0] = 255 # Set red component to maximum + >>> pic = Picture(image=data) + + """ + def __init__(self, path=None, size=None, color=None, image=None): + # Can only provide either path or size, but not both. + if (path and size) or (path and image) or (size and image): + assert False, "Can only provide path, size, or image." + + # Opening a particular file. Convert the image to RGB + # automatically so (r, g, b) tuples can be used + # everywhere. + elif path is not None: + self._image = skimage.img_as_ubyte(skimage.io.imread(path)) + self._path = path + self._format = imghdr.what(path) + + # Creating a particular size of image. + elif size is not None: + if color is None: + color = (0, 0, 0) + + # skimage dimensions are flipped: y, x + self._image = np.zeros((size[1], size[0], 3), "uint8") + self._image[:, :] = color + self._path = None + self._format = None + elif image is not None: + self._image = image + self._path = None + self._format = None + + # Must have provided 'path', 'size', or 'image'. + else: + assert False, "Must provide one of path, size, or image." + + # Common setup. + self._modified = False + self._inflation = 1 + + @staticmethod + def from_path(path): + """Creates a Picture from an image file. + + Parameters + ---------- + path : str + Path to the image file. + + Returns + ------- + pic : Picture + A Picture with the image file data loaded. + + """ + return Picture(path=path) + + @staticmethod + def from_color(color, size): + """Creates a single color Picture. + + Parameters + ---------- + color : tuple + RGB tuple with the fill color for the picture [0-255] + + size : tuple + Width and height of the picture in pixels. + + Returns + ------- + pic : Picture + A Picture with the given color and size. + + """ + return Picture(color=color, size=size) + + @staticmethod + def from_image(image): + """Creates a single color Picture. + + Parameters + ---------- + color : tuple + RGB tuple with the fill color for the picture [0-255] + + size : tuple + Width and height of the picture in pixels. + + Returns + ------- + pic : Picture + A Picture with the given color and size. + + """ + return Picture(image=image) + + def save(self, path): + """Saves the picture to the given path. + + Parameters + ---------- + path : str + Path to save the picture (with file extension). + + """ + skimage.io.imsave(path, self._inflate(self._image)) + self._modified = False + self._path = os.path.abspath(path) + self._format = imghdr.what(path) + + @property + def path(self): + """Gets the path of the picture. + + Returns + ------- + path : str + The absolute path of the picture or None if modified. + + """ + return self._path + + @property + def modified(self): + """Gets a value indicating if the picture has changed. + + Returns + ------- + modified : bool + True if the picture has been changed, False otherwise. + + """ + return self._modified + + @property + def format(self): + """Gets the format of the picture. + + Returns + ------- + format : str + File format of the picture (e.g., png, jpeg) or None if not saved. + + """ + return self._format + + @property + def size(self): + """Gets size of the picture. + + Returns + ------- + size : tuple + Width and height of the picture in pixels. + + """ + # skimage dimensions are flipped: y, x + return (self._image.shape[1], self._image.shape[0]) + + @size.setter + def size(self, value): + """Sets the size of the picture. + + Parameters + ---------- + value : tuple + Desired width and height of the picture. Will resize image as necessary. + + """ + try: + # Don't resize if no change in size + if (value[0] != self.width) or (value[1] != self.height): + # skimage dimensions are flipped: y, x + self._image = skimage.img_as_ubyte(skimage.transform.resize(self._image, + (int(value[1]), int(value[0])), order=0)) + + self._modified = True + self._path = None + except TypeError: + raise TypeError("Expected (width, height), but got {0} instead!".format(value)) + + @property + def width(self): + """Gets the width of the picture. + + Returns + ------- + width : int + Width of the picture in pixels. + + """ + return self.size[0] + + @width.setter + def width(self, value): + """Sets the width of the picture. + + Parameters + ------- + value : int + Desired width of the picture in pixels. Will resize the image as necessary. + + """ + self.size = (value, self.height) + + @property + def height(self): + """Gets the height of the picture. + + Returns + ------- + height : int + Height of the picture in pixels. + + """ + return self.size[1] + + @height.setter + def height(self, value): + """Sets the height of the picture. + + Parameters + ------- + value : int + Desired height of the picture in pixels. Will resize the image as necessary. + + """ + self.size = (self.width, value) + + @property + def inflation(self): + """Gets the inflation factor. + + Returns + ------- + inflation : int + Factor to scale each pixel by when saving or viewing (1 = no inflation). + + """ + return self._inflation + + @inflation.setter + def inflation(self, value): + """Sets the inflation factor. + + Parameters + ---------- + value : int + Factor to scale each pixel by when saving or viewing (1 = no inflation). + + """ + try: + value = int(value) + if value < 1: + raise ValueError() + self._inflation = value + except ValueError: + raise ValueError("Expected inflation factor to be an integer greater than one") + + def _repr_html_(self): + return skimage.io.Image(self._inflate(self._image)) + + def _repr_png_(self): + return skimage.io.Image(self._inflate(self._image)) + + def show(self): + """Displays the image in a separate window. + + """ + skimage.io.imshow(self._inflate(self._image)) + + def _makepixel(self, xy): + """ Creates a Pixel object for a given x, y location. + + Parameters + ---------- + xy : tuple + Cartesian coordinates to create a Pixel object for. + + """ + # skimage dimensions are flipped: y, x + rgb = self._image[self.height - xy[1] - 1, xy[0]] + return Pixel(self, self._image, xy[0], xy[1], rgb) + + def _inflate(self, img): + """Inflates image according to inflation factor. + + Parameters + ---------- + img : array_like + Raw RGB image data to inflate using nearest neighbor algorithm. + + """ + if self._inflation == 1: + return img + + # skimage dimensions are flipped: y, x + return img_as_ubyte(skimage.transform.resize(img, + (self.height * self._inflation, + self.width * self._inflation), order=0)) + + def __iter__(self): + """Iterates over all pixels in the image. + + """ + for x in xrange(self.width): + for y in xrange(self.height): + yield self._makepixel((x, y)) + + def __getitem__(self, key): + """Gets pixels using 2D int or slice notations. + + Parameters + ---------- + key : tuple + Horizontal and vertical coordinates or slices. + + Returns + ------- + p: Pixel or PixelGroup + Single pixel for coordinates or PixelGroup for slice. + + Examples + -------- + Get the bottom-left pixel + + >>> pic[0, 0] + + Get the top row of the picture + + >>> pic[:, pic.height-1] + + """ + if isinstance(key, tuple) and len(key) == 2: + if isinstance(key[0], int) and isinstance(key[1], int): + if key[0] < 0 or key[1] < 0: + raise IndexError("Negative indices not supported") + + return self._makepixel((key[0], key[1])) + else: + return PixelGroup(self, key) + else: + raise TypeError("Invalid key type") + + def __setitem__(self, key, value): + """Sets pixel values using 2D int or slice notations. + + Parameters + ---------- + key : tuple + Horizontal and vertical coordinates or slices. + value : tuple + RGB tuple with red, green, and blue components [0-255] + + Examples + -------- + Set the bottom-left pixel to black + + >>> pic[0, 0] = (0, 0, 0) + + Set the top row to red + + >>> pic[:, pic.height-1] = (255, 0, 0) + + """ + if isinstance(key, tuple) and len(key) == 2: + if isinstance(value, tuple): + self[key[0], key[1]].rgb = value + elif isinstance(value, PixelGroup): + src_key = self[key[0], key[1]]._key + self._image[src_key] = value._image[value._key] + else: + raise TypeError("Invalid value type") + else: + raise TypeError("Invalid key type") + + def __repr__(self): + return "Picture (format: {0}, path: {1}, modified: {2})".format(self.format, self.path, self.modified) + diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py new file mode 100644 index 00000000..21451968 --- /dev/null +++ b/skimage/novice/tests/test_novice.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Tests for novice submodule. +:license: modified BSD +""" + +import os, tempfile +from numpy.testing import TestCase, assert_equal, assert_raises +from skimage import novice, data_dir + +class TestNovice(TestCase): + sample_path = os.path.join(data_dir, "elephant.png") + small_sample_path = os.path.join(data_dir, "block.png") + + def test_pic_info(self): + pic = novice.open(self.sample_path) + assert_equal(pic.format, "png") + assert_equal(pic.path, os.path.abspath(self.sample_path)) + assert_equal(pic.size, (665, 500)) + assert_equal(pic.width, 665) + assert_equal(pic.height, 500) + assert_equal(pic.modified, False) + assert_equal(pic.inflation, 1) + + num_pixels = sum(1 for p in pic) + assert_equal(num_pixels, pic.width * pic.height) + + def test_modify(self): + pic = novice.open(self.small_sample_path) + assert_equal(pic.modified, False) + + for p in pic: + if p.x < (pic.width / 2): + p.red /= 2 + p.green /= 2 + p.blue /= 2 + + for p in pic: + if p.x < (pic.width / 2): + assert_equal(p.red <= 128, True) + assert_equal(p.green <= 128, True) + assert_equal(p.blue <= 128, True) + + s = pic.size + pic.size = (pic.width / 2, pic.height / 2) + assert_equal(pic.size, (int(s[0] / 2), int(s[1] / 2))) + + assert_equal(pic.modified, True) + assert_equal(pic.path, None) + + with tempfile.NamedTemporaryFile(suffix=".jpg") as tmp: + pic.save(tmp.name) + + assert_equal(pic.modified, False) + assert_equal(pic.path, os.path.abspath(tmp.name)) + assert_equal(pic.format, "jpeg") + + def test_indexing(self): + pic = novice.open(self.small_sample_path) + + # Slicing + pic[0:5, 0:5] = (0, 0, 0) + for p in pic: + if (p.x < 5) and (p.y < 5): + assert_equal(p.rgb, (0, 0, 0)) + assert_equal(p.red, 0) + assert_equal(p.green, 0) + assert_equal(p.blue, 0) + + pic[:5, :5] = (255, 255, 255) + for p in pic: + if (p.x < 5) and (p.y < 5): + assert_equal(p.rgb, (255, 255, 255)) + assert_equal(p.red, 255) + assert_equal(p.green, 255) + assert_equal(p.blue, 255) + + pic[5:pic.width, 5:pic.height] = (255, 0, 255) + for p in pic: + if (p.x >= 5) and (p.y >= 5): + assert_equal(p.rgb, (255, 0, 255)) + assert_equal(p.red, 255) + assert_equal(p.green, 0) + assert_equal(p.blue, 255) + + pic[5:, 5:] = (0, 0, 255) + for p in pic: + if (p.x >= 5) and (p.y >= 5): + assert_equal(p.rgb, (0, 0, 255)) + assert_equal(p.red, 0) + assert_equal(p.green, 0) + assert_equal(p.blue, 255) + + # Outside bounds + assert_raises(IndexError, lambda: pic[pic.width, pic.height]) + + # Negative indexing not supported + assert_raises(IndexError, lambda: pic[-1, -1]) + assert_raises(IndexError, lambda: pic[-1:, -1:]) + + # Step sizes > 1 not supported + assert_raises(IndexError, lambda: pic[::2, ::2]) + + def test_slicing(self): + cut = 40 + pic = novice.open(self.sample_path) + rest = pic.width - cut + temp = pic[:cut, :] + pic[:rest, :] = pic[cut:, :] + pic[rest:, :] = temp + + pic_orig = novice.open(self.sample_path) + + # Check center line + half_height = int(pic.height/2) + for p1 in pic_orig[rest:, half_height]: + for p2 in pic[:cut, half_height]: + assert p1.rgb == p2.rgb + + for p1 in pic_orig[:cut, half_height]: + for p2 in pic[rest:, half_height]: + assert p1.rgb == p2.rgb From bd51d9cbef40e6a47ce2fe8b5ef04c2816537e1b Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Thu, 20 Jun 2013 21:32:20 -0500 Subject: [PATCH 02/51] Fix whitespace --- skimage/novice/novice.py | 74 ++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/skimage/novice/novice.py b/skimage/novice/novice.py index 0744afc5..b6bc3bb1 100644 --- a/skimage/novice/novice.py +++ b/skimage/novice/novice.py @@ -2,7 +2,7 @@ import os, numpy as np, imghdr from skimage.util import img_as_ubyte import skimage.io, skimage.transform -# ================================================== +# ================================================== class Pixel(object): """A single pixel in a Picture. @@ -38,7 +38,7 @@ class Pixel(object): ------- x : int The horizontal location of the pixel. - + """ return self._x @@ -50,7 +50,7 @@ class Pixel(object): ------- y : int The vertical location of the pixel. - + """ return self._y @@ -73,7 +73,7 @@ class Pixel(object): ---------- value : int Red component of the pixel (0-255) - + """ self._red = self._validate(value) self._setpixel() @@ -97,7 +97,7 @@ class Pixel(object): ---------- value : int Green component of the pixel (0-255) - + """ self._green = self._validate(value) self._setpixel() @@ -121,7 +121,7 @@ class Pixel(object): ---------- value : int Blue component of the pixel (0-255) - + """ self._blue = self._validate(value) self._setpixel() @@ -134,7 +134,7 @@ class Pixel(object): ---------- color : tuple RGB tuple with red, green, and blue components (0-255) - + """ return (self.red, self.green, self.blue) @@ -146,7 +146,7 @@ class Pixel(object): ---------- value : tuple RGB tuple with red, green, and blue components (0-255) - + """ for v in value: self._validate(v) @@ -158,7 +158,7 @@ class Pixel(object): def _validate(self, value): """Verifies that the pixel value is in [0, 255]. - + """ try: value = int(value) @@ -185,7 +185,7 @@ class Pixel(object): def __repr__(self): return "Pixel (red: {0}, green: {1}, blue: {2})".format(self.red, self.green, self.blue) -# ================================================== +# ================================================== class PixelGroup(object): """A group of Pixel objects that can be manipulated together. @@ -273,7 +273,7 @@ class PixelGroup(object): ---------- value : int Red component of the pixel (0-255) - + """ self._setdim(0, value) @@ -296,7 +296,7 @@ class PixelGroup(object): ---------- value : int green component of the pixel (0-255) - + """ self._setdim(1, value) @@ -319,7 +319,7 @@ class PixelGroup(object): ---------- value : int blue component of the pixel (0-255) - + """ self._setdim(2, value) @@ -331,7 +331,7 @@ class PixelGroup(object): ---------- color : tuple RGB tuple with red, green, and blue components (0-255) - + """ return self._getdim(None) @@ -343,7 +343,7 @@ class PixelGroup(object): ---------- value : tuple RGB tuple with red, green, and blue components (0-255) - + """ self._setdim(None, value) @@ -361,7 +361,7 @@ class PixelGroup(object): def __repr__(self): return "PixelGroup ({0} pixels)".format(self.size[0] * self.size[1]) -# ================================================== +# ================================================== class Picture(object): """A 2-D picture made up of pixels. @@ -495,12 +495,12 @@ class Picture(object): def save(self, path): """Saves the picture to the given path. - + Parameters ---------- path : str Path to save the picture (with file extension). - + """ skimage.io.imsave(path, self._inflate(self._image)) self._modified = False @@ -515,14 +515,14 @@ class Picture(object): ------- path : str The absolute path of the picture or None if modified. - + """ return self._path @property def modified(self): """Gets a value indicating if the picture has changed. - + Returns ------- modified : bool @@ -534,7 +534,7 @@ class Picture(object): @property def format(self): """Gets the format of the picture. - + Returns ------- format : str @@ -546,12 +546,12 @@ class Picture(object): @property def size(self): """Gets size of the picture. - + Returns ------- size : tuple Width and height of the picture in pixels. - + """ # skimage dimensions are flipped: y, x return (self._image.shape[1], self._image.shape[0]) @@ -581,7 +581,7 @@ class Picture(object): @property def width(self): """Gets the width of the picture. - + Returns ------- width : int @@ -593,7 +593,7 @@ class Picture(object): @width.setter def width(self, value): """Sets the width of the picture. - + Parameters ------- value : int @@ -605,7 +605,7 @@ class Picture(object): @property def height(self): """Gets the height of the picture. - + Returns ------- height : int @@ -617,7 +617,7 @@ class Picture(object): @height.setter def height(self, value): """Sets the height of the picture. - + Parameters ------- value : int @@ -629,24 +629,24 @@ class Picture(object): @property def inflation(self): """Gets the inflation factor. - + Returns ------- inflation : int Factor to scale each pixel by when saving or viewing (1 = no inflation). - + """ return self._inflation @inflation.setter def inflation(self, value): """Sets the inflation factor. - + Parameters ---------- value : int Factor to scale each pixel by when saving or viewing (1 = no inflation). - + """ try: value = int(value) @@ -664,7 +664,7 @@ class Picture(object): def show(self): """Displays the image in a separate window. - + """ skimage.io.imshow(self._inflate(self._image)) @@ -683,24 +683,24 @@ class Picture(object): def _inflate(self, img): """Inflates image according to inflation factor. - + Parameters ---------- img : array_like Raw RGB image data to inflate using nearest neighbor algorithm. - + """ if self._inflation == 1: return img # skimage dimensions are flipped: y, x - return img_as_ubyte(skimage.transform.resize(img, + return img_as_ubyte(skimage.transform.resize(img, (self.height * self._inflation, self.width * self._inflation), order=0)) def __iter__(self): """Iterates over all pixels in the image. - + """ for x in xrange(self.width): for y in xrange(self.height): @@ -717,7 +717,7 @@ class Picture(object): Returns ------- p: Pixel or PixelGroup - Single pixel for coordinates or PixelGroup for slice. + Single pixel for coordinates or PixelGroup for slice. Examples -------- From 34a844dd3be1bb9dfb4d56fccb73f4566a1e404e Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Thu, 20 Jun 2013 21:38:20 -0500 Subject: [PATCH 03/51] Cleanups to imports and line wrapping --- skimage/novice/novice.py | 58 +++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/skimage/novice/novice.py b/skimage/novice/novice.py index b6bc3bb1..f14ea6cd 100644 --- a/skimage/novice/novice.py +++ b/skimage/novice/novice.py @@ -1,8 +1,11 @@ -import os, numpy as np, imghdr -from skimage.util import img_as_ubyte -import skimage.io, skimage.transform +import os +import imghdr + +import numpy as np +from skimage import io +from skimage import img_as_ubyte +from skimage.transform import resize -# ================================================== class Pixel(object): """A single pixel in a Picture. @@ -165,7 +168,8 @@ class Pixel(object): if (value < 0) or (value > 255): raise ValueError() except ValueError: - raise ValueError("Expected an integer between 0 and 255, but got {0} instead!".format(value)) + msg = "Expected an integer between 0 and 255, but got {0} instead!" + raise ValueError(msg.format(value)) return value @@ -183,9 +187,9 @@ class Pixel(object): self._picture._picture_modified = True def __repr__(self): - return "Pixel (red: {0}, green: {1}, blue: {2})".format(self.red, self.green, self.blue) + args = self.red, self.green, self.blue + return "Pixel (red: {0}, green: {1}, blue: {2})".format(*args) -# ================================================== class PixelGroup(object): """A group of Pixel objects that can be manipulated together. @@ -361,7 +365,6 @@ class PixelGroup(object): def __repr__(self): return "PixelGroup ({0} pixels)".format(self.size[0] * self.size[1]) -# ================================================== class Picture(object): """A 2-D picture made up of pixels. @@ -409,7 +412,7 @@ class Picture(object): # automatically so (r, g, b) tuples can be used # everywhere. elif path is not None: - self._image = skimage.img_as_ubyte(skimage.io.imread(path)) + self._image = img_as_ubyte(io.imread(path)) self._path = path self._format = imghdr.what(path) @@ -502,7 +505,7 @@ class Picture(object): Path to save the picture (with file extension). """ - skimage.io.imsave(path, self._inflate(self._image)) + io.imsave(path, self._inflate(self._image)) self._modified = False self._path = os.path.abspath(path) self._format = imghdr.what(path) @@ -563,20 +566,22 @@ class Picture(object): Parameters ---------- value : tuple - Desired width and height of the picture. Will resize image as necessary. + Desired width and height of the picture. Will resize image as + necessary. """ try: # Don't resize if no change in size if (value[0] != self.width) or (value[1] != self.height): # skimage dimensions are flipped: y, x - self._image = skimage.img_as_ubyte(skimage.transform.resize(self._image, + self._image = img_as_ubyte(resize(self._image, (int(value[1]), int(value[0])), order=0)) self._modified = True self._path = None except TypeError: - raise TypeError("Expected (width, height), but got {0} instead!".format(value)) + msg = "Expected (width, height), but got {0} instead!" + raise TypeError(msg.format(value)) @property def width(self): @@ -597,7 +602,8 @@ class Picture(object): Parameters ------- value : int - Desired width of the picture in pixels. Will resize the image as necessary. + Desired width of the picture in pixels. Will resize the image as + necessary. """ self.size = (value, self.height) @@ -621,7 +627,8 @@ class Picture(object): Parameters ------- value : int - Desired height of the picture in pixels. Will resize the image as necessary. + Desired height of the picture in pixels. Will resize the image as + necessary. """ self.size = (self.width, value) @@ -633,7 +640,8 @@ class Picture(object): Returns ------- inflation : int - Factor to scale each pixel by when saving or viewing (1 = no inflation). + Factor to scale each pixel by when saving or viewing (1 = no + inflation). """ return self._inflation @@ -645,7 +653,8 @@ class Picture(object): Parameters ---------- value : int - Factor to scale each pixel by when saving or viewing (1 = no inflation). + Factor to scale each pixel by when saving or viewing (1 = no + inflation). """ try: @@ -654,19 +663,20 @@ class Picture(object): raise ValueError() self._inflation = value except ValueError: - raise ValueError("Expected inflation factor to be an integer greater than one") + msg = "Expected inflation factor to be an integer greater than one" + raise ValueError(msg) def _repr_html_(self): - return skimage.io.Image(self._inflate(self._image)) + return io.Image(self._inflate(self._image)) def _repr_png_(self): - return skimage.io.Image(self._inflate(self._image)) + return io.Image(self._inflate(self._image)) def show(self): """Displays the image in a separate window. """ - skimage.io.imshow(self._inflate(self._image)) + io.imshow(self._inflate(self._image)) def _makepixel(self, xy): """ Creates a Pixel object for a given x, y location. @@ -694,7 +704,7 @@ class Picture(object): return img # skimage dimensions are flipped: y, x - return img_as_ubyte(skimage.transform.resize(img, + return img_as_ubyte(resize(img, (self.height * self._inflation, self.width * self._inflation), order=0)) @@ -774,5 +784,5 @@ class Picture(object): raise TypeError("Invalid key type") def __repr__(self): - return "Picture (format: {0}, path: {1}, modified: {2})".format(self.format, self.path, self.modified) - + args = self.format, self.path, self.modified + return "Picture (format: {0}, path: {1}, modified: {2})".format(*args) From 1a418f8820a1a084671ca5b35892d0114b1fe837 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Thu, 20 Jun 2013 22:06:07 -0500 Subject: [PATCH 04/51] Clean up novice __init__ Move functions from __init__ to novice module and clean up package docstring. Doctest now passes. --- skimage/novice/__init__.py | 112 +++++++++++++++++++------------------ skimage/novice/novice.py | 21 +++++++ 2 files changed, 79 insertions(+), 54 deletions(-) diff --git a/skimage/novice/__init__.py b/skimage/novice/__init__.py index bde59b3f..e80c389f 100644 --- a/skimage/novice/__init__.py +++ b/skimage/novice/__init__.py @@ -5,65 +5,69 @@ A special Python image submodule for beginners. Description ----------- -skimage.novice provides a simple image manipulation interface for beginners. -It allows for easy loading, manipulating, and saving of image files. +``skimage.novice`` provides a simple image manipulation interface for +beginners. It allows for easy loading, manipulating, and saving of image +files. + +This module is primarily intended for teaching and differs significantly from +the normal, array-oriented image functions used by scikit-image. + +.. note:: + + This module uses the Cartesian coordinate system, where the origin is at + the lower-left corner instead of the upper-right. -NOTE: This module uses the Cartesian coordinate system! Example ------- - >>> from skimage import novice # special submodule for beginners +We can create a Picture object open opening an image file +>>> from skimage import novice +>>> from skimage import data +>>> picture = novice.open(data.data_dir + '/elephant.png') + +Pictures know their format +>>> print picture.format +png + +... and where they came from +>>> print picture.path.endswith('elephant.png') +True + +... and their size +>>> print picture.size +(665, 500) +>>> print picture.width +665 + +Changing `size` resizes the picture. +>>> picture.size = (200, 250) + +You can iterate over pixels, which have RGB values between 0 and 255, +and know their location in the picture. +>>> for pixel in picture: +... if (pixel.red > 128) and (pixel.x < picture.width): +... pixel.red /= 2 + +Pictures know if they've been modified from the original file +>>> print picture.modified +True +>>> print picture.path +None + +Pictures can be indexed like arrays +>>> picture[0:20, 0:20] = (0, 0, 0) + +Saving the picture updates the path attribute, format, and modified state. +>>> picture.save('sample-bluegreen.jpg') +>>> print picture.path.endswith('sample-bluegreen.jpg') +True +>>> print picture.format +jpeg +>>> print picture.modified +False - >>> picture = novice.open('sample.png') # create a picture object from a file - >>> print picture.format # pictures know their format... - 'png' - >>> print picture.path # ...and where they came from... - '/Users/example/sample.png' - >>> print picture.size # ...and their size - (665, 500) - >>> print picture.width # 'width' and 'height' also exposed - 665 - >>> picture.size = (200, 250) # changing size automatically resizes - >>> for pixel in picture: # can iterate over pixels - >>> ... if ((pixel.red > 128) and # pixels have RGB (values are 0-255)... - >>> ... (pixel.x < picture.width)): # ...and know where they are - >>> ... pixel.red /= 2 # pixel is an alias into the picture - >>> ... - >>> print picture.modified # pictures know if their pixels are dirty - True - >>> print picture.path # picture no longer corresponds to file - None - >>> picture[0:20, 0:20] = (0, 0, 0) # overwrite lower-left rectangle with black - >>> picture.save('sample-bluegreen.jpg') # guess file type from suffix - >>> print picture.path # picture now corresponds to file - '/Users/example/sample-bluegreen.jpg' - >>> print picture.format # ...has a different format - jpeg - >>> print picture.modified # and is now in sync - False """ -import os as _os -from .colors import * -from .novice import Picture - -def open(path): - """ - Creates a new Picture object from the given image path - """ - return Picture(path=_os.path.abspath(path)) - -def new(size, color=None): - """ - Create a new RGB picture of the given size, initialized to the - given color or to black if none is provided. - """ - return Picture(size=size, color=color) - -def copy(image): - """ - Creates a Picture using the supplied image data - (e.g., skimage.data.elephant()). - """ - return Picture(image=image) +from . import colors +from .novice import Picture, open, new, copy diff --git a/skimage/novice/novice.py b/skimage/novice/novice.py index f14ea6cd..1130dbcb 100644 --- a/skimage/novice/novice.py +++ b/skimage/novice/novice.py @@ -7,6 +7,27 @@ from skimage import img_as_ubyte from skimage.transform import resize +def open(path): + """ + Creates a new Picture object from the given image path + """ + return Picture(path=os.path.abspath(path)) + +def new(size, color=None): + """ + Create a new RGB picture of the given size, initialized to the + given color or to black if none is provided. + """ + return Picture(size=size, color=color) + +def copy(image): + """ + Creates a Picture using the supplied image data + (e.g., skimage.data.elephant()). + """ + return Picture(image=image) + + class Pixel(object): """A single pixel in a Picture. From 22a7558673e406cb2f2c4e8df9fb6f5ce63bd563 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Thu, 20 Jun 2013 22:17:35 -0500 Subject: [PATCH 05/51] Change test class to test functions --- skimage/novice/tests/test_novice.py | 209 ++++++++++++++-------------- 1 file changed, 107 insertions(+), 102 deletions(-) diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 21451968..50134a86 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -1,123 +1,128 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +import os +import tempfile -"""Tests for novice submodule. -:license: modified BSD -""" +from numpy.testing import assert_equal, assert_raises +from skimage import novice +from skimage import data_dir -import os, tempfile -from numpy.testing import TestCase, assert_equal, assert_raises -from skimage import novice, data_dir -class TestNovice(TestCase): - sample_path = os.path.join(data_dir, "elephant.png") - small_sample_path = os.path.join(data_dir, "block.png") +IMAGE_PATH = os.path.join(data_dir, "elephant.png") +SMALL_IMAGE_PATH = os.path.join(data_dir, "block.png") + + +def test_pic_info(): + pic = novice.open(IMAGE_PATH) + assert_equal(pic.format, "png") + assert_equal(pic.path, os.path.abspath(IMAGE_PATH)) + assert_equal(pic.size, (665, 500)) + assert_equal(pic.width, 665) + assert_equal(pic.height, 500) + assert_equal(pic.modified, False) + assert_equal(pic.inflation, 1) + + num_pixels = sum(1 for p in pic) + assert_equal(num_pixels, pic.width * pic.height) + + +def test_modify(): + pic = novice.open(SMALL_IMAGE_PATH) + assert_equal(pic.modified, False) + + for p in pic: + if p.x < (pic.width / 2): + p.red /= 2 + p.green /= 2 + p.blue /= 2 + + for p in pic: + if p.x < (pic.width / 2): + assert_equal(p.red <= 128, True) + assert_equal(p.green <= 128, True) + assert_equal(p.blue <= 128, True) + + s = pic.size + pic.size = (pic.width / 2, pic.height / 2) + assert_equal(pic.size, (int(s[0] / 2), int(s[1] / 2))) + + assert_equal(pic.modified, True) + assert_equal(pic.path, None) + + with tempfile.NamedTemporaryFile(suffix=".jpg") as tmp: + pic.save(tmp.name) - def test_pic_info(self): - pic = novice.open(self.sample_path) - assert_equal(pic.format, "png") - assert_equal(pic.path, os.path.abspath(self.sample_path)) - assert_equal(pic.size, (665, 500)) - assert_equal(pic.width, 665) - assert_equal(pic.height, 500) assert_equal(pic.modified, False) - assert_equal(pic.inflation, 1) + assert_equal(pic.path, os.path.abspath(tmp.name)) + assert_equal(pic.format, "jpeg") - num_pixels = sum(1 for p in pic) - assert_equal(num_pixels, pic.width * pic.height) - def test_modify(self): - pic = novice.open(self.small_sample_path) - assert_equal(pic.modified, False) +def test_indexing(): + pic = novice.open(SMALL_IMAGE_PATH) - for p in pic: - if p.x < (pic.width / 2): - p.red /= 2 - p.green /= 2 - p.blue /= 2 + # Slicing + pic[0:5, 0:5] = (0, 0, 0) + for p in pic: + if (p.x < 5) and (p.y < 5): + assert_equal(p.rgb, (0, 0, 0)) + assert_equal(p.red, 0) + assert_equal(p.green, 0) + assert_equal(p.blue, 0) - for p in pic: - if p.x < (pic.width / 2): - assert_equal(p.red <= 128, True) - assert_equal(p.green <= 128, True) - assert_equal(p.blue <= 128, True) + pic[:5, :5] = (255, 255, 255) + for p in pic: + if (p.x < 5) and (p.y < 5): + assert_equal(p.rgb, (255, 255, 255)) + assert_equal(p.red, 255) + assert_equal(p.green, 255) + assert_equal(p.blue, 255) - s = pic.size - pic.size = (pic.width / 2, pic.height / 2) - assert_equal(pic.size, (int(s[0] / 2), int(s[1] / 2))) + pic[5:pic.width, 5:pic.height] = (255, 0, 255) + for p in pic: + if (p.x >= 5) and (p.y >= 5): + assert_equal(p.rgb, (255, 0, 255)) + assert_equal(p.red, 255) + assert_equal(p.green, 0) + assert_equal(p.blue, 255) - assert_equal(pic.modified, True) - assert_equal(pic.path, None) + pic[5:, 5:] = (0, 0, 255) + for p in pic: + if (p.x >= 5) and (p.y >= 5): + assert_equal(p.rgb, (0, 0, 255)) + assert_equal(p.red, 0) + assert_equal(p.green, 0) + assert_equal(p.blue, 255) - with tempfile.NamedTemporaryFile(suffix=".jpg") as tmp: - pic.save(tmp.name) + # Outside bounds + assert_raises(IndexError, lambda: pic[pic.width, pic.height]) - assert_equal(pic.modified, False) - assert_equal(pic.path, os.path.abspath(tmp.name)) - assert_equal(pic.format, "jpeg") + # Negative indexing not supported + assert_raises(IndexError, lambda: pic[-1, -1]) + assert_raises(IndexError, lambda: pic[-1:, -1:]) - def test_indexing(self): - pic = novice.open(self.small_sample_path) + # Step sizes > 1 not supported + assert_raises(IndexError, lambda: pic[::2, ::2]) - # Slicing - pic[0:5, 0:5] = (0, 0, 0) - for p in pic: - if (p.x < 5) and (p.y < 5): - assert_equal(p.rgb, (0, 0, 0)) - assert_equal(p.red, 0) - assert_equal(p.green, 0) - assert_equal(p.blue, 0) - pic[:5, :5] = (255, 255, 255) - for p in pic: - if (p.x < 5) and (p.y < 5): - assert_equal(p.rgb, (255, 255, 255)) - assert_equal(p.red, 255) - assert_equal(p.green, 255) - assert_equal(p.blue, 255) +def test_slicing(): + cut = 40 + pic = novice.open(IMAGE_PATH) + rest = pic.width - cut + temp = pic[:cut, :] + pic[:rest, :] = pic[cut:, :] + pic[rest:, :] = temp - pic[5:pic.width, 5:pic.height] = (255, 0, 255) - for p in pic: - if (p.x >= 5) and (p.y >= 5): - assert_equal(p.rgb, (255, 0, 255)) - assert_equal(p.red, 255) - assert_equal(p.green, 0) - assert_equal(p.blue, 255) + pic_orig = novice.open(IMAGE_PATH) - pic[5:, 5:] = (0, 0, 255) - for p in pic: - if (p.x >= 5) and (p.y >= 5): - assert_equal(p.rgb, (0, 0, 255)) - assert_equal(p.red, 0) - assert_equal(p.green, 0) - assert_equal(p.blue, 255) + # Check center line + half_height = int(pic.height/2) + for p1 in pic_orig[rest:, half_height]: + for p2 in pic[:cut, half_height]: + assert p1.rgb == p2.rgb - # Outside bounds - assert_raises(IndexError, lambda: pic[pic.width, pic.height]) + for p1 in pic_orig[:cut, half_height]: + for p2 in pic[rest:, half_height]: + assert p1.rgb == p2.rgb - # Negative indexing not supported - assert_raises(IndexError, lambda: pic[-1, -1]) - assert_raises(IndexError, lambda: pic[-1:, -1:]) - # Step sizes > 1 not supported - assert_raises(IndexError, lambda: pic[::2, ::2]) - - def test_slicing(self): - cut = 40 - pic = novice.open(self.sample_path) - rest = pic.width - cut - temp = pic[:cut, :] - pic[:rest, :] = pic[cut:, :] - pic[rest:, :] = temp - - pic_orig = novice.open(self.sample_path) - - # Check center line - half_height = int(pic.height/2) - for p1 in pic_orig[rest:, half_height]: - for p2 in pic[:cut, half_height]: - assert p1.rgb == p2.rgb - - for p1 in pic_orig[:cut, half_height]: - for p2 in pic[rest:, half_height]: - assert p1.rgb == p2.rgb +if __name__ == '__main__': + from numpy import testing + testing.run_module_suite() From a2f03d307510637f47f42e207d4277e5caf11f8e Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Thu, 20 Jun 2013 22:30:08 -0500 Subject: [PATCH 06/51] Speed up test --- skimage/novice/tests/test_novice.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 50134a86..737554a2 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -20,6 +20,9 @@ def test_pic_info(): assert_equal(pic.modified, False) assert_equal(pic.inflation, 1) + +def test_pixel_iteration(): + pic = novice.open(SMALL_IMAGE_PATH) num_pixels = sum(1 for p in pic) assert_equal(num_pixels, pic.width * pic.height) From 9503c41f26c427700c74c27b28e741e4c2f2fd3d Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Thu, 20 Jun 2013 23:02:18 -0500 Subject: [PATCH 07/51] Cleanup docstrings. Note that the getter (not setter) docstring gets printed at the interactive prompt --- skimage/novice/__init__.py | 3 +- skimage/novice/novice.py | 265 ++++--------------------------------- 2 files changed, 25 insertions(+), 243 deletions(-) diff --git a/skimage/novice/__init__.py b/skimage/novice/__init__.py index e80c389f..3256e22b 100644 --- a/skimage/novice/__init__.py +++ b/skimage/novice/__init__.py @@ -15,7 +15,8 @@ the normal, array-oriented image functions used by scikit-image. .. note:: This module uses the Cartesian coordinate system, where the origin is at - the lower-left corner instead of the upper-right. + the lower-left corner instead of the upper-right and the order is x, y + instead of row, column. Example diff --git a/skimage/novice/novice.py b/skimage/novice/novice.py index 1130dbcb..067d9379 100644 --- a/skimage/novice/novice.py +++ b/skimage/novice/novice.py @@ -56,122 +56,51 @@ class Pixel(object): @property def x(self): - """Gets the horizontal location (left = 0). - - Returns - ------- - x : int - The horizontal location of the pixel. - - """ + """Horizontal location of this pixel in the parent image(left = 0).""" return self._x @property def y(self): - """Gets the vertical location (bottom = 0). - - Returns - ------- - y : int - The vertical location of the pixel. - - """ + """Vertical location of this pixel in the parent image (bottom = 0).""" return self._y @property def red(self): - """Gets the red component of the pixel. - - Returns - ------- - value : int - The red component of the pixel (0-255). - """ + """The red component of the pixel (0-255).""" return self._red @red.setter def red(self, value): - """Sets the red component of the pixel. - - Parameters - ---------- - value : int - Red component of the pixel (0-255) - - """ self._red = self._validate(value) self._setpixel() @property def green(self): - """Gets the green component of the pixel. - - Returns - ------- - value : int - The green component of the pixel (0-255). - """ + """The green component of the pixel (0-255).""" return self._green @green.setter def green(self, value): - """Sets the green component of the pixel. - - Parameters - ---------- - value : int - Green component of the pixel (0-255) - - """ self._green = self._validate(value) self._setpixel() @property def blue(self): - """Gets the blue component of the pixel. - - Returns - ------- - value : int - The blue component of the pixel (0-255). - """ + """The blue component of the pixel (0-255).""" return self._blue @blue.setter def blue(self, value): - """Sets the blue component of the pixel. - - Parameters - ---------- - value : int - Blue component of the pixel (0-255) - - """ self._blue = self._validate(value) self._setpixel() @property def rgb(self): - """Gets the RGB color of the pixel. - - Returns - ---------- - color : tuple - RGB tuple with red, green, and blue components (0-255) - - """ + """The RGB color components of the pixel (3 values 0-255).""" return (self.red, self.green, self.blue) @rgb.setter def rgb(self, value): - """Sets the RGB color of the pixel. - - Parameters - ---------- - value : tuple - RGB tuple with red, green, and blue components (0-255) - - """ for v in value: self._validate(v) @@ -181,9 +110,7 @@ class Pixel(object): self._setpixel() def _validate(self, value): - """Verifies that the pixel value is in [0, 255]. - - """ + """Verifies that the pixel value is in [0, 255].""" try: value = int(value) if (value < 0) or (value > 255): @@ -196,6 +123,7 @@ class Pixel(object): def _setpixel(self): """Sets the actual pixel value in the picture. + NOTE: Using Cartesian coordinate system! """ @@ -244,9 +172,7 @@ class PixelGroup(object): if dim_slice.step is not None and dim_slice.step != 1: raise IndexError("Only a step size of 1 is supported") - # =========== # Flip y axis - # =========== y_slice = key[1] start = y_slice.start if y_slice.start is not None else 0 stop = y_slice.stop if y_slice.stop is not None else pic.height @@ -256,7 +182,7 @@ class PixelGroup(object): key = (key[0], slice(stop, start + 1, y_slice.step)) - # skimage dimensions are flipped: y, x + # array dimensions are row, column (i.e. y, x) self._key = (key[1], key[0]) self._image = pic._image @@ -281,95 +207,38 @@ class PixelGroup(object): @property def red(self): - """Gets the red component of the pixel. - - Returns - ------- - value : int - The red component of the pixel (0-255). - """ + """The red component of the pixel (0-255).""" return self._getdim(0).ravel() @red.setter def red(self, value): - """Sets the red component of the pixel. - - Parameters - ---------- - value : int - Red component of the pixel (0-255) - - """ self._setdim(0, value) @property def green(self): - """Gets the green component of the pixel. - - Returns - ------- - value : int - The green component of the pixel (0-255). - """ + """The green component of the pixel (0-255).""" return self._getdim(1).ravel() @green.setter def green(self, value): - """Sets the green component of the pixel. - - Parameters - ---------- - value : int - green component of the pixel (0-255) - - """ self._setdim(1, value) @property def blue(self): - """Gets the blue component of the pixel. - - Returns - ------- - value : int - The blue component of the pixel (0-255). - """ + """The blue component of the pixel (0-255).""" return self._getdim(2).ravel() @blue.setter def blue(self, value): - """Sets the blue component of the pixel. - - Parameters - ---------- - value : int - blue component of the pixel (0-255) - - """ self._setdim(2, value) @property def rgb(self): - """Gets the RGB color of the pixel. - - Returns - ---------- - color : tuple - RGB tuple with red, green, and blue components (0-255) - - """ + """The RGB color components of the pixel (3 values 0-255).""" return self._getdim(None) @rgb.setter def rgb(self, value): - """Sets the RGB color of the pixel. - - Parameters - ---------- - value : tuple - RGB tuple with red, green, and blue components (0-255) - - """ self._setdim(None, value) def __iter__(self): @@ -533,64 +402,27 @@ class Picture(object): @property def path(self): - """Gets the path of the picture. - - Returns - ------- - path : str - The absolute path of the picture or None if modified. - - """ + """The path to the picture.""" return self._path @property def modified(self): - """Gets a value indicating if the picture has changed. - - Returns - ------- - modified : bool - True if the picture has been changed, False otherwise. - - """ + """True if the picture has changed.""" return self._modified @property def format(self): - """Gets the format of the picture. - - Returns - ------- - format : str - File format of the picture (e.g., png, jpeg) or None if not saved. - - """ + """The image format of the picture.""" return self._format @property def size(self): - """Gets size of the picture. - - Returns - ------- - size : tuple - Width and height of the picture in pixels. - - """ - # skimage dimensions are flipped: y, x + """The size (width, height) of the picture.""" + # array dimensions are flipped: y, x return (self._image.shape[1], self._image.shape[0]) @size.setter def size(self, value): - """Sets the size of the picture. - - Parameters - ---------- - value : tuple - Desired width and height of the picture. Will resize image as - necessary. - - """ try: # Don't resize if no change in size if (value[0] != self.width) or (value[1] != self.height): @@ -606,78 +438,29 @@ class Picture(object): @property def width(self): - """Gets the width of the picture. - - Returns - ------- - width : int - Width of the picture in pixels. - - """ + """The width of the picture.""" return self.size[0] @width.setter def width(self, value): - """Sets the width of the picture. - - Parameters - ------- - value : int - Desired width of the picture in pixels. Will resize the image as - necessary. - - """ self.size = (value, self.height) @property def height(self): - """Gets the height of the picture. - - Returns - ------- - height : int - Height of the picture in pixels. - - """ + """The height of the picture.""" return self.size[1] @height.setter def height(self, value): - """Sets the height of the picture. - - Parameters - ------- - value : int - Desired height of the picture in pixels. Will resize the image as - necessary. - - """ self.size = (self.width, value) @property def inflation(self): - """Gets the inflation factor. - - Returns - ------- - inflation : int - Factor to scale each pixel by when saving or viewing (1 = no - inflation). - - """ + """The inflation factor.""" return self._inflation @inflation.setter def inflation(self, value): - """Sets the inflation factor. - - Parameters - ---------- - value : int - Factor to scale each pixel by when saving or viewing (1 = no - inflation). - - """ try: value = int(value) if value < 1: @@ -717,7 +500,7 @@ class Picture(object): Parameters ---------- - img : array_like + img : array Raw RGB image data to inflate using nearest neighbor algorithm. """ @@ -730,9 +513,7 @@ class Picture(object): self.width * self._inflation), order=0)) def __iter__(self): - """Iterates over all pixels in the image. - - """ + """Iterates over all pixels in the image.""" for x in xrange(self.width): for y in xrange(self.height): yield self._makepixel((x, y)) From 62c16bde51fbd31879d4f641605b3e6190019c9c Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Thu, 20 Jun 2013 23:15:30 -0500 Subject: [PATCH 08/51] Remove color scraping script and intermediate data file --- skimage/novice/colors.csv | 865 ---------------------------------- skimage/novice/make_colors.py | 60 --- 2 files changed, 925 deletions(-) delete mode 100644 skimage/novice/colors.csv delete mode 100644 skimage/novice/make_colors.py diff --git a/skimage/novice/colors.csv b/skimage/novice/colors.csv deleted file mode 100644 index 05e78540..00000000 --- a/skimage/novice/colors.csv +++ /dev/null @@ -1,865 +0,0 @@ -air_force_blue_raf,"Air Force Blue (Raf)",#5d8aa8,93,138,168 -air_force_blue_usaf,"Air Force Blue (Usaf)",#00308f,0,48,143 -air_superiority_blue,"Air Superiority Blue",#72a0c1,114,160,193 -alabama_crimson,"Alabama Crimson",#a32638,163,38,56 -alice_blue,"Alice Blue",#f0f8ff,240,248,255 -alizarin_crimson,"Alizarin Crimson",#e32636,227,38,54 -alloy_orange,"Alloy Orange",#c46210,196,98,16 -almond,Almond,#efdecd,239,222,205 -amaranth,Amaranth,#e52b50,229,43,80 -amber,Amber,#ffbf00,255,191,0 -amber_sae_ece,"Amber (Sae/Ece)",#ff7e00,255,126,0 -american_rose,"American Rose",#ff033e,255,3,62 -amethyst,Amethyst,#96c,153,102,204 -android_green,"Android Green",#a4c639,164,198,57 -anti_flash_white,"Anti-Flash White",#f2f3f4,242,243,244 -antique_brass,"Antique Brass",#cd9575,205,149,117 -antique_fuchsia,"Antique Fuchsia",#915c83,145,92,131 -antique_ruby,"Antique Ruby",#841b2d,132,27,45 -antique_white,"Antique White",#faebd7,250,235,215 -ao_english,"Ao (English)",#008000,0,128,0 -apple_green,"Apple Green",#8db600,141,182,0 -apricot,Apricot,#fbceb1,251,206,177 -aqua,Aqua,#0ff,0,255,255 -aquamarine,Aquamarine,#7fffd4,127,255,212 -army_green,"Army Green",#4b5320,75,83,32 -arsenic,Arsenic,#3b444b,59,68,75 -arylide_yellow,"Arylide Yellow",#e9d66b,233,214,107 -ash_grey,"Ash Grey",#b2beb5,178,190,181 -asparagus,Asparagus,#87a96b,135,169,107 -atomic_tangerine,"Atomic Tangerine",#f96,255,153,102 -auburn,Auburn,#a52a2a,165,42,42 -aureolin,Aureolin,#fdee00,253,238,0 -aurometalsaurus,Aurometalsaurus,#6e7f80,110,127,128 -avocado,Avocado,#568203,86,130,3 -azure,Azure,#007fff,0,127,255 -azure_mist_web,"Azure Mist/Web",#f0ffff,240,255,255 -baby_blue,"Baby Blue",#89cff0,137,207,240 -baby_blue_eyes,"Baby Blue Eyes",#a1caf1,161,202,241 -baby_pink,"Baby Pink",#f4c2c2,244,194,194 -ball_blue,"Ball Blue",#21abcd,33,171,205 -banana_mania,"Banana Mania",#fae7b5,250,231,181 -banana_yellow,"Banana Yellow",#ffe135,255,225,53 -barn_red,"Barn Red",#7c0a02,124,10,2 -battleship_grey,"Battleship Grey",#848482,132,132,130 -bazaar,Bazaar,#98777b,152,119,123 -beau_blue,"Beau Blue",#bcd4e6,188,212,230 -beaver,Beaver,#9f8170,159,129,112 -beige,Beige,#f5f5dc,245,245,220 -big_dip_o_ruby,"Big Dip O’Ruby",#9c2542,156,37,66 -bisque,Bisque,#ffe4c4,255,228,196 -bistre,Bistre,#3d2b1f,61,43,31 -bittersweet,Bittersweet,#fe6f5e,254,111,94 -bittersweet_shimmer,"Bittersweet Shimmer",#bf4f51,191,79,81 -black,Black,#000,0,0,0 -black_bean,"Black Bean",#3d0c02,61,12,2 -black_leather_jacket,"Black Leather Jacket",#253529,37,53,41 -black_olive,"Black Olive",#3b3c36,59,60,54 -blanched_almond,"Blanched Almond",#ffebcd,255,235,205 -blast_off_bronze,"Blast-Off Bronze",#a57164,165,113,100 -bleu_de_france,"Bleu De France",#318ce7,49,140,231 -blizzard_blue,"Blizzard Blue",#ace5ee,172,229,238 -blond,Blond,#faf0be,250,240,190 -blue,Blue,#00f,0,0,255 -blue_bell,"Blue Bell",#a2a2d0,162,162,208 -blue_crayola,"Blue (Crayola)",#1f75fe,31,117,254 -blue_gray,"Blue Gray",#69c,102,153,204 -blue_green,Blue-Green,#0d98ba,13,152,186 -blue_munsell,"Blue (Munsell)",#0093af,0,147,175 -blue_ncs,"Blue (Ncs)",#0087bd,0,135,189 -blue_pigment,"Blue (Pigment)",#339,51,51,153 -blue_ryb,"Blue (Ryb)",#0247fe,2,71,254 -blue_sapphire,"Blue Sapphire",#126180,18,97,128 -blue_violet,Blue-Violet,#8a2be2,138,43,226 -blush,Blush,#de5d83,222,93,131 -bole,Bole,#79443b,121,68,59 -bondi_blue,"Bondi Blue",#0095b6,0,149,182 -bone,Bone,#e3dac9,227,218,201 -boston_university_red,"Boston University Red",#c00,204,0,0 -bottle_green,"Bottle Green",#006a4e,0,106,78 -boysenberry,Boysenberry,#873260,135,50,96 -brandeis_blue,"Brandeis Blue",#0070ff,0,112,255 -brass,Brass,#b5a642,181,166,66 -brick_red,"Brick Red",#cb4154,203,65,84 -bright_cerulean,"Bright Cerulean",#1dacd6,29,172,214 -bright_green,"Bright Green",#6f0,102,255,0 -bright_lavender,"Bright Lavender",#bf94e4,191,148,228 -bright_maroon,"Bright Maroon",#c32148,195,33,72 -bright_pink,"Bright Pink",#ff007f,255,0,127 -bright_turquoise,"Bright Turquoise",#08e8de,8,232,222 -bright_ube,"Bright Ube",#d19fe8,209,159,232 -brilliant_lavender,"Brilliant Lavender",#f4bbff,244,187,255 -brilliant_rose,"Brilliant Rose",#ff55a3,255,85,163 -brink_pink,"Brink Pink",#fb607f,251,96,127 -british_racing_green,"British Racing Green",#004225,0,66,37 -bronze,Bronze,#cd7f32,205,127,50 -brown_traditional,"Brown (Traditional)",#964b00,150,75,0 -brown_web,"Brown (Web)",#a52a2a,165,42,42 -bubble_gum,"Bubble Gum",#ffc1cc,255,193,204 -bubbles,Bubbles,#e7feff,231,254,255 -buff,Buff,#f0dc82,240,220,130 -bulgarian_rose,"Bulgarian Rose",#480607,72,6,7 -burgundy,Burgundy,#800020,128,0,32 -burlywood,Burlywood,#deb887,222,184,135 -burnt_orange,"Burnt Orange",#c50,204,85,0 -burnt_sienna,"Burnt Sienna",#e97451,233,116,81 -burnt_umber,"Burnt Umber",#8a3324,138,51,36 -byzantine,Byzantine,#bd33a4,189,51,164 -byzantium,Byzantium,#702963,112,41,99 -cadet,Cadet,#536872,83,104,114 -cadet_blue,"Cadet Blue",#5f9ea0,95,158,160 -cadet_grey,"Cadet Grey",#91a3b0,145,163,176 -cadmium_green,"Cadmium Green",#006b3c,0,107,60 -cadmium_orange,"Cadmium Orange",#ed872d,237,135,45 -cadmium_red,"Cadmium Red",#e30022,227,0,34 -cadmium_yellow,"Cadmium Yellow",#fff600,255,246,0 -caf_au_lait,"Café Au Lait",#a67b5b,166,123,91 -caf_noir,"Café Noir",#4b3621,75,54,33 -cal_poly_green,"Cal Poly Green",#1e4d2b,30,77,43 -cambridge_blue,"Cambridge Blue",#a3c1ad,163,193,173 -camel,Camel,#c19a6b,193,154,107 -cameo_pink,"Cameo Pink",#efbbcc,239,187,204 -camouflage_green,"Camouflage Green",#78866b,120,134,107 -canary_yellow,"Canary Yellow",#ffef00,255,239,0 -candy_apple_red,"Candy Apple Red",#ff0800,255,8,0 -candy_pink,"Candy Pink",#e4717a,228,113,122 -capri,Capri,#00bfff,0,191,255 -caput_mortuum,"Caput Mortuum",#592720,89,39,32 -cardinal,Cardinal,#c41e3a,196,30,58 -caribbean_green,"Caribbean Green",#0c9,0,204,153 -carmine,Carmine,#960018,150,0,24 -carmine_m_p,"Carmine (M&P)",#d70040,215,0,64 -carmine_pink,"Carmine Pink",#eb4c42,235,76,66 -carmine_red,"Carmine Red",#ff0038,255,0,56 -carnation_pink,"Carnation Pink",#ffa6c9,255,166,201 -carnelian,Carnelian,#b31b1b,179,27,27 -carolina_blue,"Carolina Blue",#99badd,153,186,221 -carrot_orange,"Carrot Orange",#ed9121,237,145,33 -catalina_blue,"Catalina Blue",#062a78,6,42,120 -ceil,Ceil,#92a1cf,146,161,207 -celadon,Celadon,#ace1af,172,225,175 -celadon_blue,"Celadon Blue",#007ba7,0,123,167 -celadon_green,"Celadon Green",#2f847c,47,132,124 -celeste_colour,"Celeste (Colour)",#b2ffff,178,255,255 -celestial_blue,"Celestial Blue",#4997d0,73,151,208 -cerise,Cerise,#de3163,222,49,99 -cerise_pink,"Cerise Pink",#ec3b83,236,59,131 -cerulean,Cerulean,#007ba7,0,123,167 -cerulean_blue,"Cerulean Blue",#2a52be,42,82,190 -cerulean_frost,"Cerulean Frost",#6d9bc3,109,155,195 -cg_blue,"Cg Blue",#007aa5,0,122,165 -cg_red,"Cg Red",#e03c31,224,60,49 -chamoisee,Chamoisee,#a0785a,160,120,90 -champagne,Champagne,#fad6a5,250,214,165 -charcoal,Charcoal,#36454f,54,69,79 -charm_pink,"Charm Pink",#e68fac,230,143,172 -chartreuse_traditional,"Chartreuse (Traditional)",#dfff00,223,255,0 -chartreuse_web,"Chartreuse (Web)",#7fff00,127,255,0 -cherry,Cherry,#de3163,222,49,99 -cherry_blossom_pink,"Cherry Blossom Pink",#ffb7c5,255,183,197 -chestnut,Chestnut,#cd5c5c,205,92,92 -china_pink,"China Pink",#de6fa1,222,111,161 -china_rose,"China Rose",#a8516e,168,81,110 -chinese_red,"Chinese Red",#aa381e,170,56,30 -chocolate_traditional,"Chocolate (Traditional)",#7b3f00,123,63,0 -chocolate_web,"Chocolate (Web)",#d2691e,210,105,30 -chrome_yellow,"Chrome Yellow",#ffa700,255,167,0 -cinereous,Cinereous,#98817b,152,129,123 -cinnabar,Cinnabar,#e34234,227,66,52 -cinnamon,Cinnamon,#d2691e,210,105,30 -citrine,Citrine,#e4d00a,228,208,10 -classic_rose,"Classic Rose",#fbcce7,251,204,231 -cobalt,Cobalt,#0047ab,0,71,171 -cocoa_brown,"Cocoa Brown",#d2691e,210,105,30 -coffee,Coffee,#6f4e37,111,78,55 -columbia_blue,"Columbia Blue",#9bddff,155,221,255 -congo_pink,"Congo Pink",#f88379,248,131,121 -cool_black,"Cool Black",#002e63,0,46,99 -cool_grey,"Cool Grey",#8c92ac,140,146,172 -copper,Copper,#b87333,184,115,51 -copper_crayola,"Copper (Crayola)",#da8a67,218,138,103 -copper_penny,"Copper Penny",#ad6f69,173,111,105 -copper_red,"Copper Red",#cb6d51,203,109,81 -copper_rose,"Copper Rose",#966,153,102,102 -coquelicot,Coquelicot,#ff3800,255,56,0 -coral,Coral,#ff7f50,255,127,80 -coral_pink,"Coral Pink",#f88379,248,131,121 -coral_red,"Coral Red",#ff4040,255,64,64 -cordovan,Cordovan,#893f45,137,63,69 -corn,Corn,#fbec5d,251,236,93 -cornell_red,"Cornell Red",#b31b1b,179,27,27 -cornflower_blue,"Cornflower Blue",#6495ed,100,149,237 -cornsilk,Cornsilk,#fff8dc,255,248,220 -cosmic_latte,"Cosmic Latte",#fff8e7,255,248,231 -cotton_candy,"Cotton Candy",#ffbcd9,255,188,217 -cream,Cream,#fffdd0,255,253,208 -crimson,Crimson,#dc143c,220,20,60 -crimson_glory,"Crimson Glory",#be0032,190,0,50 -cyan,Cyan,#0ff,0,255,255 -cyan_process,"Cyan (Process)",#00b7eb,0,183,235 -daffodil,Daffodil,#ffff31,255,255,49 -dandelion,Dandelion,#f0e130,240,225,48 -dark_blue,"Dark Blue",#00008b,0,0,139 -dark_brown,"Dark Brown",#654321,101,67,33 -dark_byzantium,"Dark Byzantium",#5d3954,93,57,84 -dark_candy_apple_red,"Dark Candy Apple Red",#a40000,164,0,0 -dark_cerulean,"Dark Cerulean",#08457e,8,69,126 -dark_chestnut,"Dark Chestnut",#986960,152,105,96 -dark_coral,"Dark Coral",#cd5b45,205,91,69 -dark_cyan,"Dark Cyan",#008b8b,0,139,139 -dark_electric_blue,"Dark Electric Blue",#536878,83,104,120 -dark_goldenrod,"Dark Goldenrod",#b8860b,184,134,11 -dark_gray,"Dark Gray",#a9a9a9,169,169,169 -dark_green,"Dark Green",#013220,1,50,32 -dark_imperial_blue,"Dark Imperial Blue",#00416a,0,65,106 -dark_jungle_green,"Dark Jungle Green",#1a2421,26,36,33 -dark_khaki,"Dark Khaki",#bdb76b,189,183,107 -dark_lava,"Dark Lava",#483c32,72,60,50 -dark_lavender,"Dark Lavender",#734f96,115,79,150 -dark_magenta,"Dark Magenta",#8b008b,139,0,139 -dark_midnight_blue,"Dark Midnight Blue",#036,0,51,102 -dark_olive_green,"Dark Olive Green",#556b2f,85,107,47 -dark_orange,"Dark Orange",#ff8c00,255,140,0 -dark_orchid,"Dark Orchid",#9932cc,153,50,204 -dark_pastel_blue,"Dark Pastel Blue",#779ecb,119,158,203 -dark_pastel_green,"Dark Pastel Green",#03c03c,3,192,60 -dark_pastel_purple,"Dark Pastel Purple",#966fd6,150,111,214 -dark_pastel_red,"Dark Pastel Red",#c23b22,194,59,34 -dark_pink,"Dark Pink",#e75480,231,84,128 -dark_powder_blue,"Dark Powder Blue",#039,0,51,153 -dark_raspberry,"Dark Raspberry",#872657,135,38,87 -dark_red,"Dark Red",#8b0000,139,0,0 -dark_salmon,"Dark Salmon",#e9967a,233,150,122 -dark_scarlet,"Dark Scarlet",#560319,86,3,25 -dark_sea_green,"Dark Sea Green",#8fbc8f,143,188,143 -dark_sienna,"Dark Sienna",#3c1414,60,20,20 -dark_slate_blue,"Dark Slate Blue",#483d8b,72,61,139 -dark_slate_gray,"Dark Slate Gray",#2f4f4f,47,79,79 -dark_spring_green,"Dark Spring Green",#177245,23,114,69 -dark_tan,"Dark Tan",#918151,145,129,81 -dark_tangerine,"Dark Tangerine",#ffa812,255,168,18 -dark_taupe,"Dark Taupe",#483c32,72,60,50 -dark_terra_cotta,"Dark Terra Cotta",#cc4e5c,204,78,92 -dark_turquoise,"Dark Turquoise",#00ced1,0,206,209 -dark_violet,"Dark Violet",#9400d3,148,0,211 -dark_yellow,"Dark Yellow",#9b870c,155,135,12 -dartmouth_green,"Dartmouth Green",#00703c,0,112,60 -davy_s_grey,"Davy'S Grey",#555,85,85,85 -debian_red,"Debian Red",#d70a53,215,10,83 -deep_carmine,"Deep Carmine",#a9203e,169,32,62 -deep_carmine_pink,"Deep Carmine Pink",#ef3038,239,48,56 -deep_carrot_orange,"Deep Carrot Orange",#e9692c,233,105,44 -deep_cerise,"Deep Cerise",#da3287,218,50,135 -deep_champagne,"Deep Champagne",#fad6a5,250,214,165 -deep_chestnut,"Deep Chestnut",#b94e48,185,78,72 -deep_coffee,"Deep Coffee",#704241,112,66,65 -deep_fuchsia,"Deep Fuchsia",#c154c1,193,84,193 -deep_jungle_green,"Deep Jungle Green",#004b49,0,75,73 -deep_lilac,"Deep Lilac",#95b,153,85,187 -deep_magenta,"Deep Magenta",#c0c,204,0,204 -deep_peach,"Deep Peach",#ffcba4,255,203,164 -deep_pink,"Deep Pink",#ff1493,255,20,147 -deep_ruby,"Deep Ruby",#843f5b,132,63,91 -deep_saffron,"Deep Saffron",#f93,255,153,51 -deep_sky_blue,"Deep Sky Blue",#00bfff,0,191,255 -deep_tuscan_red,"Deep Tuscan Red",#66424d,102,66,77 -denim,Denim,#1560bd,21,96,189 -desert,Desert,#c19a6b,193,154,107 -desert_sand,"Desert Sand",#edc9af,237,201,175 -dim_gray,"Dim Gray",#696969,105,105,105 -dodger_blue,"Dodger Blue",#1e90ff,30,144,255 -dogwood_rose,"Dogwood Rose",#d71868,215,24,104 -dollar_bill,"Dollar Bill",#85bb65,133,187,101 -drab,Drab,#967117,150,113,23 -duke_blue,"Duke Blue",#00009c,0,0,156 -earth_yellow,"Earth Yellow",#e1a95f,225,169,95 -ebony,Ebony,#555d50,85,93,80 -ecru,Ecru,#c2b280,194,178,128 -eggplant,Eggplant,#614051,97,64,81 -eggshell,Eggshell,#f0ead6,240,234,214 -egyptian_blue,"Egyptian Blue",#1034a6,16,52,166 -electric_blue,"Electric Blue",#7df9ff,125,249,255 -electric_crimson,"Electric Crimson",#ff003f,255,0,63 -electric_cyan,"Electric Cyan",#0ff,0,255,255 -electric_green,"Electric Green",#0f0,0,255,0 -electric_indigo,"Electric Indigo",#6f00ff,111,0,255 -electric_lavender,"Electric Lavender",#f4bbff,244,187,255 -electric_lime,"Electric Lime",#cf0,204,255,0 -electric_purple,"Electric Purple",#bf00ff,191,0,255 -electric_ultramarine,"Electric Ultramarine",#3f00ff,63,0,255 -electric_violet,"Electric Violet",#8f00ff,143,0,255 -electric_yellow,"Electric Yellow",#ff0,255,255,0 -emerald,Emerald,#50c878,80,200,120 -english_lavender,"English Lavender",#b48395,180,131,149 -eton_blue,"Eton Blue",#96c8a2,150,200,162 -fallow,Fallow,#c19a6b,193,154,107 -falu_red,"Falu Red",#801818,128,24,24 -fandango,Fandango,#b53389,181,51,137 -fashion_fuchsia,"Fashion Fuchsia",#f400a1,244,0,161 -fawn,Fawn,#e5aa70,229,170,112 -feldgrau,Feldgrau,#4d5d53,77,93,83 -fern_green,"Fern Green",#4f7942,79,121,66 -ferrari_red,"Ferrari Red",#ff2800,255,40,0 -field_drab,"Field Drab",#6c541e,108,84,30 -fire_engine_red,"Fire Engine Red",#ce2029,206,32,41 -firebrick,Firebrick,#b22222,178,34,34 -flame,Flame,#e25822,226,88,34 -flamingo_pink,"Flamingo Pink",#fc8eac,252,142,172 -flavescent,Flavescent,#f7e98e,247,233,142 -flax,Flax,#eedc82,238,220,130 -floral_white,"Floral White",#fffaf0,255,250,240 -fluorescent_orange,"Fluorescent Orange",#ffbf00,255,191,0 -fluorescent_pink,"Fluorescent Pink",#ff1493,255,20,147 -fluorescent_yellow,"Fluorescent Yellow",#cf0,204,255,0 -folly,Folly,#ff004f,255,0,79 -forest_green_traditional,"Forest Green (Traditional)",#014421,1,68,33 -forest_green_web,"Forest Green (Web)",#228b22,34,139,34 -french_beige,"French Beige",#a67b5b,166,123,91 -french_blue,"French Blue",#0072bb,0,114,187 -french_lilac,"French Lilac",#86608e,134,96,142 -french_lime,"French Lime",#cf0,204,255,0 -french_raspberry,"French Raspberry",#c72c48,199,44,72 -french_rose,"French Rose",#f64a8a,246,74,138 -fuchsia,Fuchsia,#f0f,255,0,255 -fuchsia_crayola,"Fuchsia (Crayola)",#c154c1,193,84,193 -fuchsia_pink,"Fuchsia Pink",#f7f,255,119,255 -fuchsia_rose,"Fuchsia Rose",#c74375,199,67,117 -fulvous,Fulvous,#e48400,228,132,0 -fuzzy_wuzzy,"Fuzzy Wuzzy",#c66,204,102,102 -gainsboro,Gainsboro,#dcdcdc,220,220,220 -gamboge,Gamboge,#e49b0f,228,155,15 -ghost_white,"Ghost White",#f8f8ff,248,248,255 -ginger,Ginger,#b06500,176,101,0 -glaucous,Glaucous,#6082b6,96,130,182 -glitter,Glitter,#e6e8fa,230,232,250 -gold_metallic,"Gold (Metallic)",#d4af37,212,175,55 -gold_web_golden,"Gold (Web) (Golden)",#ffd700,255,215,0 -golden_brown,"Golden Brown",#996515,153,101,21 -golden_poppy,"Golden Poppy",#fcc200,252,194,0 -golden_yellow,"Golden Yellow",#ffdf00,255,223,0 -goldenrod,Goldenrod,#daa520,218,165,32 -granny_smith_apple,"Granny Smith Apple",#a8e4a0,168,228,160 -gray,Gray,#808080,128,128,128 -gray_asparagus,Gray-Asparagus,#465945,70,89,69 -gray_html_css_gray,"Gray (Html/Css Gray)",#808080,128,128,128 -gray_x11_gray,"Gray (X11 Gray)",#bebebe,190,190,190 -green,"Green (Color Wheel) (X11 Green)",#0f0,0,255,0 -green_crayola,"Green (Crayola)",#1cac78,28,172,120 -green_html_css_green,"Green (Html/Css Green)",#008000,0,128,0 -green_munsell,"Green (Munsell)",#00a877,0,168,119 -green_ncs,"Green (Ncs)",#009f6b,0,159,107 -green_pigment,"Green (Pigment)",#00a550,0,165,80 -green_ryb,"Green (Ryb)",#66b032,102,176,50 -green_yellow,Green-Yellow,#adff2f,173,255,47 -grullo,Grullo,#a99a86,169,154,134 -guppie_green,"Guppie Green",#00ff7f,0,255,127 -halay_be,"Halayà úBe",#663854,102,56,84 -han_blue,"Han Blue",#446ccf,68,108,207 -han_purple,"Han Purple",#5218fa,82,24,250 -hansa_yellow,"Hansa Yellow",#e9d66b,233,214,107 -harlequin,Harlequin,#3fff00,63,255,0 -harvard_crimson,"Harvard Crimson",#c90016,201,0,22 -harvest_gold,"Harvest Gold",#da9100,218,145,0 -heart_gold,"Heart Gold",#808000,128,128,0 -heliotrope,Heliotrope,#df73ff,223,115,255 -hollywood_cerise,"Hollywood Cerise",#f400a1,244,0,161 -honeydew,Honeydew,#f0fff0,240,255,240 -honolulu_blue,"Honolulu Blue",#007fbf,0,127,191 -hooker_s_green,"Hooker'S Green",#49796b,73,121,107 -hot_magenta,"Hot Magenta",#ff1dce,255,29,206 -hot_pink,"Hot Pink",#ff69b4,255,105,180 -hunter_green,"Hunter Green",#355e3b,53,94,59 -iceberg,Iceberg,#71a6d2,113,166,210 -icterine,Icterine,#fcf75e,252,247,94 -imperial_blue,"Imperial Blue",#002395,0,35,149 -inchworm,Inchworm,#b2ec5d,178,236,93 -india_green,"India Green",#138808,19,136,8 -indian_red,"Indian Red",#cd5c5c,205,92,92 -indian_yellow,"Indian Yellow",#e3a857,227,168,87 -indigo,Indigo,#6f00ff,111,0,255 -indigo_dye,"Indigo (Dye)",#00416a,0,65,106 -indigo_web,"Indigo (Web)",#4b0082,75,0,130 -international_klein_blue,"International Klein Blue",#002fa7,0,47,167 -international_orange_aerospace,"International Orange (Aerospace)",#ff4f00,255,79,0 -international_orange_engineering,"International Orange (Engineering)",#ba160c,186,22,12 -international_orange_golden_gate_bridge,"International Orange (Golden Gate Bridge)",#c0362c,192,54,44 -iris,Iris,#5a4fcf,90,79,207 -isabelline,Isabelline,#f4f0ec,244,240,236 -islamic_green,"Islamic Green",#009000,0,144,0 -ivory,Ivory,#fffff0,255,255,240 -jade,Jade,#00a86b,0,168,107 -jasmine,Jasmine,#f8de7e,248,222,126 -jasper,Jasper,#d73b3e,215,59,62 -jazzberry_jam,"Jazzberry Jam",#a50b5e,165,11,94 -jet,Jet,#343434,52,52,52 -jonquil,Jonquil,#fada5e,250,218,94 -june_bud,"June Bud",#bdda57,189,218,87 -jungle_green,"Jungle Green",#29ab87,41,171,135 -kelly_green,"Kelly Green",#4cbb17,76,187,23 -kenyan_copper,"Kenyan Copper",#7c1c05,124,28,5 -khaki_html_css_khaki,"Khaki (Html/Css) (Khaki)",#c3b091,195,176,145 -khaki_x11_light_khaki,"Khaki (X11) (Light Khaki)",#f0e68c,240,230,140 -ku_crimson,"Ku Crimson",#e8000d,232,0,13 -la_salle_green,"La Salle Green",#087830,8,120,48 -languid_lavender,"Languid Lavender",#d6cadd,214,202,221 -lapis_lazuli,"Lapis Lazuli",#26619c,38,97,156 -laser_lemon,"Laser Lemon",#fefe22,254,254,34 -laurel_green,"Laurel Green",#a9ba9d,169,186,157 -lava,Lava,#cf1020,207,16,32 -lavender_blue,"Lavender Blue",#ccf,204,204,255 -lavender_blush,"Lavender Blush",#fff0f5,255,240,245 -lavender_floral,"Lavender (Floral)",#b57edc,181,126,220 -lavender_gray,"Lavender Gray",#c4c3d0,196,195,208 -lavender_indigo,"Lavender Indigo",#9457eb,148,87,235 -lavender_magenta,"Lavender Magenta",#ee82ee,238,130,238 -lavender_mist,"Lavender Mist",#e6e6fa,230,230,250 -lavender_pink,"Lavender Pink",#fbaed2,251,174,210 -lavender_purple,"Lavender Purple",#967bb6,150,123,182 -lavender_rose,"Lavender Rose",#fba0e3,251,160,227 -lavender_web,"Lavender (Web)",#e6e6fa,230,230,250 -lawn_green,"Lawn Green",#7cfc00,124,252,0 -lemon,Lemon,#fff700,255,247,0 -lemon_chiffon,"Lemon Chiffon",#fffacd,255,250,205 -lemon_lime,"Lemon Lime",#e3ff00,227,255,0 -licorice,Licorice,#1a1110,26,17,16 -light_apricot,"Light Apricot",#fdd5b1,253,213,177 -light_blue,"Light Blue",#add8e6,173,216,230 -light_brown,"Light Brown",#b5651d,181,101,29 -light_carmine_pink,"Light Carmine Pink",#e66771,230,103,113 -light_coral,"Light Coral",#f08080,240,128,128 -light_cornflower_blue,"Light Cornflower Blue",#93ccea,147,204,234 -light_crimson,"Light Crimson",#f56991,245,105,145 -light_cyan,"Light Cyan",#e0ffff,224,255,255 -light_fuchsia_pink,"Light Fuchsia Pink",#f984ef,249,132,239 -light_goldenrod_yellow,"Light Goldenrod Yellow",#fafad2,250,250,210 -light_gray,"Light Gray",#d3d3d3,211,211,211 -light_green,"Light Green",#90ee90,144,238,144 -light_khaki,"Light Khaki",#f0e68c,240,230,140 -light_pastel_purple,"Light Pastel Purple",#b19cd9,177,156,217 -light_pink,"Light Pink",#ffb6c1,255,182,193 -light_red_ochre,"Light Red Ochre",#e97451,233,116,81 -light_salmon,"Light Salmon",#ffa07a,255,160,122 -light_salmon_pink,"Light Salmon Pink",#f99,255,153,153 -light_sea_green,"Light Sea Green",#20b2aa,32,178,170 -light_sky_blue,"Light Sky Blue",#87cefa,135,206,250 -light_slate_gray,"Light Slate Gray",#789,119,136,153 -light_taupe,"Light Taupe",#b38b6d,179,139,109 -light_thulian_pink,"Light Thulian Pink",#e68fac,230,143,172 -light_yellow,"Light Yellow",#ffffe0,255,255,224 -lilac,Lilac,#c8a2c8,200,162,200 -lime,"Lime (Color Wheel)",#bfff00,191,255,0 -lime_green,"Lime Green",#32cd32,50,205,50 -lime_web_x11_green,"Lime (Web) (X11 Green)",#0f0,0,255,0 -limerick,Limerick,#9dc209,157,194,9 -lincoln_green,"Lincoln Green",#195905,25,89,5 -linen,Linen,#faf0e6,250,240,230 -lion,Lion,#c19a6b,193,154,107 -little_boy_blue,"Little Boy Blue",#6ca0dc,108,160,220 -liver,Liver,#534b4f,83,75,79 -lust,Lust,#e62020,230,32,32 -magenta,Magenta,#f0f,255,0,255 -magenta_dye,"Magenta (Dye)",#ca1f7b,202,31,123 -magenta_process,"Magenta (Process)",#ff0090,255,0,144 -magic_mint,"Magic Mint",#aaf0d1,170,240,209 -magnolia,Magnolia,#f8f4ff,248,244,255 -mahogany,Mahogany,#c04000,192,64,0 -maize,Maize,#fbec5d,251,236,93 -majorelle_blue,"Majorelle Blue",#6050dc,96,80,220 -malachite,Malachite,#0bda51,11,218,81 -manatee,Manatee,#979aaa,151,154,170 -mango_tango,"Mango Tango",#ff8243,255,130,67 -mantis,Mantis,#74c365,116,195,101 -mardi_gras,"Mardi Gras",#880085,136,0,133 -maroon_crayola,"Maroon (Crayola)",#c32148,195,33,72 -maroon_html_css,"Maroon (Html/Css)",#800000,128,0,0 -maroon_x11,"Maroon (X11)",#b03060,176,48,96 -mauve,Mauve,#e0b0ff,224,176,255 -mauve_taupe,"Mauve Taupe",#915f6d,145,95,109 -mauvelous,Mauvelous,#ef98aa,239,152,170 -maya_blue,"Maya Blue",#73c2fb,115,194,251 -meat_brown,"Meat Brown",#e5b73b,229,183,59 -medium_aquamarine,"Medium Aquamarine",#6da,102,221,170 -medium_blue,"Medium Blue",#0000cd,0,0,205 -medium_candy_apple_red,"Medium Candy Apple Red",#e2062c,226,6,44 -medium_carmine,"Medium Carmine",#af4035,175,64,53 -medium_champagne,"Medium Champagne",#f3e5ab,243,229,171 -medium_electric_blue,"Medium Electric Blue",#035096,3,80,150 -medium_jungle_green,"Medium Jungle Green",#1c352d,28,53,45 -medium_lavender_magenta,"Medium Lavender Magenta",#dda0dd,221,160,221 -medium_orchid,"Medium Orchid",#ba55d3,186,85,211 -medium_persian_blue,"Medium Persian Blue",#0067a5,0,103,165 -medium_purple,"Medium Purple",#9370db,147,112,219 -medium_red_violet,"Medium Red-Violet",#bb3385,187,51,133 -medium_ruby,"Medium Ruby",#aa4069,170,64,105 -medium_sea_green,"Medium Sea Green",#3cb371,60,179,113 -medium_slate_blue,"Medium Slate Blue",#7b68ee,123,104,238 -medium_spring_bud,"Medium Spring Bud",#c9dc87,201,220,135 -medium_spring_green,"Medium Spring Green",#00fa9a,0,250,154 -medium_taupe,"Medium Taupe",#674c47,103,76,71 -medium_turquoise,"Medium Turquoise",#48d1cc,72,209,204 -medium_tuscan_red,"Medium Tuscan Red",#79443b,121,68,59 -medium_vermilion,"Medium Vermilion",#d9603b,217,96,59 -medium_violet_red,"Medium Violet-Red",#c71585,199,21,133 -mellow_apricot,"Mellow Apricot",#f8b878,248,184,120 -mellow_yellow,"Mellow Yellow",#f8de7e,248,222,126 -melon,Melon,#fdbcb4,253,188,180 -midnight_blue,"Midnight Blue",#191970,25,25,112 -midnight_green_eagle_green,"Midnight Green (Eagle Green)",#004953,0,73,83 -mikado_yellow,"Mikado Yellow",#ffc40c,255,196,12 -mint,Mint,#3eb489,62,180,137 -mint_cream,"Mint Cream",#f5fffa,245,255,250 -mint_green,"Mint Green",#98ff98,152,255,152 -misty_rose,"Misty Rose",#ffe4e1,255,228,225 -moccasin,Moccasin,#faebd7,250,235,215 -mode_beige,"Mode Beige",#967117,150,113,23 -moonstone_blue,"Moonstone Blue",#73a9c2,115,169,194 -mordant_red_19,"Mordant Red 19",#ae0c00,174,12,0 -moss_green,"Moss Green",#addfad,173,223,173 -mountain_meadow,"Mountain Meadow",#30ba8f,48,186,143 -mountbatten_pink,"Mountbatten Pink",#997a8d,153,122,141 -msu_green,"Msu Green",#18453b,24,69,59 -mulberry,Mulberry,#c54b8c,197,75,140 -mustard,Mustard,#ffdb58,255,219,88 -myrtle,Myrtle,#21421e,33,66,30 -nadeshiko_pink,"Nadeshiko Pink",#f6adc6,246,173,198 -napier_green,"Napier Green",#2a8000,42,128,0 -naples_yellow,"Naples Yellow",#fada5e,250,218,94 -navajo_white,"Navajo White",#ffdead,255,222,173 -navy_blue,"Navy Blue",#000080,0,0,128 -neon_carrot,"Neon Carrot",#ffa343,255,163,67 -neon_fuchsia,"Neon Fuchsia",#fe4164,254,65,100 -neon_green,"Neon Green",#39ff14,57,255,20 -new_york_pink,"New York Pink",#d7837f,215,131,127 -non_photo_blue,"Non-Photo Blue",#a4dded,164,221,237 -north_texas_green,"North Texas Green",#059033,5,144,51 -ocean_boat_blue,"Ocean Boat Blue",#0077be,0,119,190 -ochre,Ochre,#c72,204,119,34 -office_green,"Office Green",#008000,0,128,0 -old_gold,"Old Gold",#cfb53b,207,181,59 -old_lace,"Old Lace",#fdf5e6,253,245,230 -old_lavender,"Old Lavender",#796878,121,104,120 -old_mauve,"Old Mauve",#673147,103,49,71 -old_rose,"Old Rose",#c08081,192,128,129 -olive,Olive,#808000,128,128,0 -olive_drab_7,"Olive Drab #7",#3c341f,60,52,31 -olive_drab_web_olive_drab_3,"Olive Drab (Web) (Olive Drab #3)",#6b8e23,107,142,35 -olivine,Olivine,#9ab973,154,185,115 -onyx,Onyx,#353839,53,56,57 -opera_mauve,"Opera Mauve",#b784a7,183,132,167 -orange,"Orange (Color Wheel)",#ff7f00,255,127,0 -orange_peel,"Orange Peel",#ff9f00,255,159,0 -orange_red,Orange-Red,#ff4500,255,69,0 -orange_ryb,"Orange (Ryb)",#fb9902,251,153,2 -orange_web_color,"Orange (Web Color)",#ffa500,255,165,0 -orchid,Orchid,#da70d6,218,112,214 -otter_brown,"Otter Brown",#654321,101,67,33 -ou_crimson_red,"Ou Crimson Red",#900,153,0,0 -outer_space,"Outer Space",#414a4c,65,74,76 -outrageous_orange,"Outrageous Orange",#ff6e4a,255,110,74 -oxford_blue,"Oxford Blue",#002147,0,33,71 -pakistan_green,"Pakistan Green",#060,0,102,0 -palatinate_blue,"Palatinate Blue",#273be2,39,59,226 -palatinate_purple,"Palatinate Purple",#682860,104,40,96 -pale_aqua,"Pale Aqua",#bcd4e6,188,212,230 -pale_blue,"Pale Blue",#afeeee,175,238,238 -pale_brown,"Pale Brown",#987654,152,118,84 -pale_carmine,"Pale Carmine",#af4035,175,64,53 -pale_cerulean,"Pale Cerulean",#9bc4e2,155,196,226 -pale_chestnut,"Pale Chestnut",#ddadaf,221,173,175 -pale_copper,"Pale Copper",#da8a67,218,138,103 -pale_cornflower_blue,"Pale Cornflower Blue",#abcdef,171,205,239 -pale_gold,"Pale Gold",#e6be8a,230,190,138 -pale_goldenrod,"Pale Goldenrod",#eee8aa,238,232,170 -pale_green,"Pale Green",#98fb98,152,251,152 -pale_lavender,"Pale Lavender",#dcd0ff,220,208,255 -pale_magenta,"Pale Magenta",#f984e5,249,132,229 -pale_pink,"Pale Pink",#fadadd,250,218,221 -pale_plum,"Pale Plum",#dda0dd,221,160,221 -pale_red_violet,"Pale Red-Violet",#db7093,219,112,147 -pale_robin_egg_blue,"Pale Robin Egg Blue",#96ded1,150,222,209 -pale_silver,"Pale Silver",#c9c0bb,201,192,187 -pale_spring_bud,"Pale Spring Bud",#ecebbd,236,235,189 -pale_taupe,"Pale Taupe",#bc987e,188,152,126 -pale_violet_red,"Pale Violet-Red",#db7093,219,112,147 -pansy_purple,"Pansy Purple",#78184a,120,24,74 -papaya_whip,"Papaya Whip",#ffefd5,255,239,213 -paris_green,"Paris Green",#50c878,80,200,120 -pastel_blue,"Pastel Blue",#aec6cf,174,198,207 -pastel_brown,"Pastel Brown",#836953,131,105,83 -pastel_gray,"Pastel Gray",#cfcfc4,207,207,196 -pastel_green,"Pastel Green",#7d7,119,221,119 -pastel_magenta,"Pastel Magenta",#f49ac2,244,154,194 -pastel_orange,"Pastel Orange",#ffb347,255,179,71 -pastel_pink,"Pastel Pink",#dea5a4,222,165,164 -pastel_purple,"Pastel Purple",#b39eb5,179,158,181 -pastel_red,"Pastel Red",#ff6961,255,105,97 -pastel_violet,"Pastel Violet",#cb99c9,203,153,201 -pastel_yellow,"Pastel Yellow",#fdfd96,253,253,150 -patriarch,Patriarch,#800080,128,0,128 -payne_s_grey,"Payne'S Grey",#536878,83,104,120 -peach,Peach,#ffe5b4,255,229,180 -peach_crayola,"Peach (Crayola)",#ffcba4,255,203,164 -peach_orange,Peach-Orange,#fc9,255,204,153 -peach_puff,"Peach Puff",#ffdab9,255,218,185 -peach_yellow,Peach-Yellow,#fadfad,250,223,173 -pear,Pear,#d1e231,209,226,49 -pearl,Pearl,#eae0c8,234,224,200 -pearl_aqua,"Pearl Aqua",#88d8c0,136,216,192 -pearly_purple,"Pearly Purple",#b768a2,183,104,162 -peridot,Peridot,#e6e200,230,226,0 -periwinkle,Periwinkle,#ccf,204,204,255 -persian_blue,"Persian Blue",#1c39bb,28,57,187 -persian_green,"Persian Green",#00a693,0,166,147 -persian_indigo,"Persian Indigo",#32127a,50,18,122 -persian_orange,"Persian Orange",#d99058,217,144,88 -persian_pink,"Persian Pink",#f77fbe,247,127,190 -persian_plum,"Persian Plum",#701c1c,112,28,28 -persian_red,"Persian Red",#c33,204,51,51 -persian_rose,"Persian Rose",#fe28a2,254,40,162 -persimmon,Persimmon,#ec5800,236,88,0 -peru,Peru,#cd853f,205,133,63 -phlox,Phlox,#df00ff,223,0,255 -phthalo_blue,"Phthalo Blue",#000f89,0,15,137 -phthalo_green,"Phthalo Green",#123524,18,53,36 -piggy_pink,"Piggy Pink",#fddde6,253,221,230 -pine_green,"Pine Green",#01796f,1,121,111 -pink,Pink,#ffc0cb,255,192,203 -pink_lace,"Pink Lace",#ffddf4,255,221,244 -pink_orange,Pink-Orange,#f96,255,153,102 -pink_pearl,"Pink Pearl",#e7accf,231,172,207 -pink_sherbet,"Pink Sherbet",#f78fa7,247,143,167 -pistachio,Pistachio,#93c572,147,197,114 -platinum,Platinum,#e5e4e2,229,228,226 -plum_traditional,"Plum (Traditional)",#8e4585,142,69,133 -plum_web,"Plum (Web)",#dda0dd,221,160,221 -portland_orange,"Portland Orange",#ff5a36,255,90,54 -powder_blue_web,"Powder Blue (Web)",#b0e0e6,176,224,230 -princeton_orange,"Princeton Orange",#ff8f00,255,143,0 -prune,Prune,#701c1c,112,28,28 -prussian_blue,"Prussian Blue",#003153,0,49,83 -psychedelic_purple,"Psychedelic Purple",#df00ff,223,0,255 -puce,Puce,#c89,204,136,153 -pumpkin,Pumpkin,#ff7518,255,117,24 -purple_heart,"Purple Heart",#69359c,105,53,156 -purple_html_css,"Purple (Html/Css)",#800080,128,0,128 -purple_mountain_majesty,"Purple Mountain Majesty",#9678b6,150,120,182 -purple_munsell,"Purple (Munsell)",#9f00c5,159,0,197 -purple_pizzazz,"Purple Pizzazz",#fe4eda,254,78,218 -purple_taupe,"Purple Taupe",#50404d,80,64,77 -purple_x11,"Purple (X11)",#a020f0,160,32,240 -quartz,Quartz,#51484f,81,72,79 -rackley,Rackley,#5d8aa8,93,138,168 -radical_red,"Radical Red",#ff355e,255,53,94 -rajah,Rajah,#fbab60,251,171,96 -raspberry,Raspberry,#e30b5d,227,11,93 -raspberry_glace,"Raspberry Glace",#915f6d,145,95,109 -raspberry_pink,"Raspberry Pink",#e25098,226,80,152 -raspberry_rose,"Raspberry Rose",#b3446c,179,68,108 -raw_umber,"Raw Umber",#826644,130,102,68 -razzle_dazzle_rose,"Razzle Dazzle Rose",#f3c,255,51,204 -razzmatazz,Razzmatazz,#e3256b,227,37,107 -red,Red,#f00,255,0,0 -red_brown,Red-Brown,#a52a2a,165,42,42 -red_devil,"Red Devil",#860111,134,1,17 -red_munsell,"Red (Munsell)",#f2003c,242,0,60 -red_ncs,"Red (Ncs)",#c40233,196,2,51 -red_orange,Red-Orange,#ff5349,255,83,73 -red_pigment,"Red (Pigment)",#ed1c24,237,28,36 -red_ryb,"Red (Ryb)",#fe2712,254,39,18 -red_violet,Red-Violet,#c71585,199,21,133 -redwood,Redwood,#ab4e52,171,78,82 -regalia,Regalia,#522d80,82,45,128 -resolution_blue,"Resolution Blue",#002387,0,35,135 -rich_black,"Rich Black",#004040,0,64,64 -rich_brilliant_lavender,"Rich Brilliant Lavender",#f1a7fe,241,167,254 -rich_carmine,"Rich Carmine",#d70040,215,0,64 -rich_electric_blue,"Rich Electric Blue",#0892d0,8,146,208 -rich_lavender,"Rich Lavender",#a76bcf,167,107,207 -rich_lilac,"Rich Lilac",#b666d2,182,102,210 -rich_maroon,"Rich Maroon",#b03060,176,48,96 -rifle_green,"Rifle Green",#414833,65,72,51 -robin_egg_blue,"Robin Egg Blue",#0cc,0,204,204 -rose,Rose,#ff007f,255,0,127 -rose_bonbon,"Rose Bonbon",#f9429e,249,66,158 -rose_ebony,"Rose Ebony",#674846,103,72,70 -rose_gold,"Rose Gold",#b76e79,183,110,121 -rose_madder,"Rose Madder",#e32636,227,38,54 -rose_pink,"Rose Pink",#f6c,255,102,204 -rose_quartz,"Rose Quartz",#aa98a9,170,152,169 -rose_taupe,"Rose Taupe",#905d5d,144,93,93 -rose_vale,"Rose Vale",#ab4e52,171,78,82 -rosewood,Rosewood,#65000b,101,0,11 -rosso_corsa,"Rosso Corsa",#d40000,212,0,0 -rosy_brown,"Rosy Brown",#bc8f8f,188,143,143 -royal_azure,"Royal Azure",#0038a8,0,56,168 -royal_blue_traditional,"Royal Blue (Traditional)",#002366,0,35,102 -royal_blue_web,"Royal Blue (Web)",#4169e1,65,105,225 -royal_fuchsia,"Royal Fuchsia",#ca2c92,202,44,146 -royal_purple,"Royal Purple",#7851a9,120,81,169 -royal_yellow,"Royal Yellow",#fada5e,250,218,94 -rubine_red,"Rubine Red",#d10056,209,0,86 -ruby,Ruby,#e0115f,224,17,95 -ruby_red,"Ruby Red",#9b111e,155,17,30 -ruddy,Ruddy,#ff0028,255,0,40 -ruddy_brown,"Ruddy Brown",#bb6528,187,101,40 -ruddy_pink,"Ruddy Pink",#e18e96,225,142,150 -rufous,Rufous,#a81c07,168,28,7 -russet,Russet,#80461b,128,70,27 -rust,Rust,#b7410e,183,65,14 -rusty_red,"Rusty Red",#da2c43,218,44,67 -sacramento_state_green,"Sacramento State Green",#00563f,0,86,63 -saddle_brown,"Saddle Brown",#8b4513,139,69,19 -safety_orange_blaze_orange,"Safety Orange (Blaze Orange)",#ff6700,255,103,0 -saffron,Saffron,#f4c430,244,196,48 -salmon,Salmon,#ff8c69,255,140,105 -salmon_pink,"Salmon Pink",#ff91a4,255,145,164 -sand,Sand,#c2b280,194,178,128 -sand_dune,"Sand Dune",#967117,150,113,23 -sandstorm,Sandstorm,#ecd540,236,213,64 -sandy_brown,"Sandy Brown",#f4a460,244,164,96 -sandy_taupe,"Sandy Taupe",#967117,150,113,23 -sangria,Sangria,#92000a,146,0,10 -sap_green,"Sap Green",#507d2a,80,125,42 -sapphire,Sapphire,#0f52ba,15,82,186 -sapphire_blue,"Sapphire Blue",#0067a5,0,103,165 -satin_sheen_gold,"Satin Sheen Gold",#cba135,203,161,53 -scarlet,Scarlet,#ff2400,255,36,0 -scarlet_crayola,"Scarlet (Crayola)",#fd0e35,253,14,53 -school_bus_yellow,"School Bus Yellow",#ffd800,255,216,0 -screamin_green,"Screamin' Green",#76ff7a,118,255,122 -sea_blue,"Sea Blue",#006994,0,105,148 -sea_green,"Sea Green",#2e8b57,46,139,87 -seal_brown,"Seal Brown",#321414,50,20,20 -seashell,Seashell,#fff5ee,255,245,238 -selective_yellow,"Selective Yellow",#ffba00,255,186,0 -sepia,Sepia,#704214,112,66,20 -shadow,Shadow,#8a795d,138,121,93 -shamrock_green,"Shamrock Green",#009e60,0,158,96 -shocking_pink,"Shocking Pink",#fc0fc0,252,15,192 -shocking_pink_crayola,"Shocking Pink (Crayola)",#ff6fff,255,111,255 -sienna,Sienna,#882d17,136,45,23 -silver,Silver,#c0c0c0,192,192,192 -sinopia,Sinopia,#cb410b,203,65,11 -skobeloff,Skobeloff,#007474,0,116,116 -sky_blue,"Sky Blue",#87ceeb,135,206,235 -sky_magenta,"Sky Magenta",#cf71af,207,113,175 -slate_blue,"Slate Blue",#6a5acd,106,90,205 -slate_gray,"Slate Gray",#708090,112,128,144 -smalt_dark_powder_blue,"Smalt (Dark Powder Blue)",#039,0,51,153 -smokey_topaz,"Smokey Topaz",#933d41,147,61,65 -smoky_black,"Smoky Black",#100c08,16,12,8 -snow,Snow,#fffafa,255,250,250 -spiro_disco_ball,"Spiro Disco Ball",#0fc0fc,15,192,252 -spring_bud,"Spring Bud",#a7fc00,167,252,0 -spring_green,"Spring Green",#00ff7f,0,255,127 -st_patrick_s_blue,"St. Patrick'S Blue",#23297a,35,41,122 -steel_blue,"Steel Blue",#4682b4,70,130,180 -stil_de_grain_yellow,"Stil De Grain Yellow",#fada5e,250,218,94 -stizza,Stizza,#900,153,0,0 -stormcloud,Stormcloud,#4f666a,79,102,106 -straw,Straw,#e4d96f,228,217,111 -sunglow,Sunglow,#fc3,255,204,51 -sunset,Sunset,#fad6a5,250,214,165 -tan,Tan,#d2b48c,210,180,140 -tangelo,Tangelo,#f94d00,249,77,0 -tangerine,Tangerine,#f28500,242,133,0 -tangerine_yellow,"Tangerine Yellow",#fc0,255,204,0 -tango_pink,"Tango Pink",#e4717a,228,113,122 -taupe,Taupe,#483c32,72,60,50 -taupe_gray,"Taupe Gray",#8b8589,139,133,137 -tea_green,"Tea Green",#d0f0c0,208,240,192 -tea_rose_orange,"Tea Rose (Orange)",#f88379,248,131,121 -tea_rose_rose,"Tea Rose (Rose)",#f4c2c2,244,194,194 -teal,Teal,#008080,0,128,128 -teal_blue,"Teal Blue",#367588,54,117,136 -teal_green,"Teal Green",#00827f,0,130,127 -telemagenta,Telemagenta,#cf3476,207,52,118 -tenn_tawny,"Tenné (Tawny)",#cd5700,205,87,0 -terra_cotta,"Terra Cotta",#e2725b,226,114,91 -thistle,Thistle,#d8bfd8,216,191,216 -thulian_pink,"Thulian Pink",#de6fa1,222,111,161 -tickle_me_pink,"Tickle Me Pink",#fc89ac,252,137,172 -tiffany_blue,"Tiffany Blue",#0abab5,10,186,181 -tiger_s_eye,"Tiger'S Eye",#e08d3c,224,141,60 -timberwolf,Timberwolf,#dbd7d2,219,215,210 -titanium_yellow,"Titanium Yellow",#eee600,238,230,0 -tomato,Tomato,#ff6347,255,99,71 -toolbox,Toolbox,#746cc0,116,108,192 -topaz,Topaz,#ffc87c,255,200,124 -tractor_red,"Tractor Red",#fd0e35,253,14,53 -trolley_grey,"Trolley Grey",#808080,128,128,128 -tropical_rain_forest,"Tropical Rain Forest",#00755e,0,117,94 -true_blue,"True Blue",#0073cf,0,115,207 -tufts_blue,"Tufts Blue",#417dc1,65,125,193 -tumbleweed,Tumbleweed,#deaa88,222,170,136 -turkish_rose,"Turkish Rose",#b57281,181,114,129 -turquoise,Turquoise,#30d5c8,48,213,200 -turquoise_blue,"Turquoise Blue",#00ffef,0,255,239 -turquoise_green,"Turquoise Green",#a0d6b4,160,214,180 -tuscan_red,"Tuscan Red",#7c4848,124,72,72 -twilight_lavender,"Twilight Lavender",#8a496b,138,73,107 -tyrian_purple,"Tyrian Purple",#66023c,102,2,60 -ua_blue,"Ua Blue",#03a,0,51,170 -ua_red,"Ua Red",#d9004c,217,0,76 -ube,Ube,#8878c3,136,120,195 -ucla_blue,"Ucla Blue",#536895,83,104,149 -ucla_gold,"Ucla Gold",#ffb300,255,179,0 -ufo_green,"Ufo Green",#3cd070,60,208,112 -ultra_pink,"Ultra Pink",#ff6fff,255,111,255 -ultramarine,Ultramarine,#120a8f,18,10,143 -ultramarine_blue,"Ultramarine Blue",#4166f5,65,102,245 -umber,Umber,#635147,99,81,71 -unbleached_silk,"Unbleached Silk",#ffddca,255,221,202 -united_nations_blue,"United Nations Blue",#5b92e5,91,146,229 -university_of_california_gold,"University Of California Gold",#b78727,183,135,39 -unmellow_yellow,"Unmellow Yellow",#ff6,255,255,102 -up_forest_green,"Up Forest Green",#014421,1,68,33 -up_maroon,"Up Maroon",#7b1113,123,17,19 -upsdell_red,"Upsdell Red",#ae2029,174,32,41 -urobilin,Urobilin,#e1ad21,225,173,33 -usafa_blue,"Usafa Blue",#004f98,0,79,152 -usc_cardinal,"Usc Cardinal",#900,153,0,0 -usc_gold,"Usc Gold",#fc0,255,204,0 -utah_crimson,"Utah Crimson",#d3003f,211,0,63 -vanilla,Vanilla,#f3e5ab,243,229,171 -vegas_gold,"Vegas Gold",#c5b358,197,179,88 -venetian_red,"Venetian Red",#c80815,200,8,21 -verdigris,Verdigris,#43b3ae,67,179,174 -vermilion_cinnabar,"Vermilion (Cinnabar)",#e34234,227,66,52 -vermilion_plochere,"Vermilion (Plochere)",#d9603b,217,96,59 -veronica,Veronica,#a020f0,160,32,240 -violet,Violet,#8f00ff,143,0,255 -violet_blue,Violet-Blue,#324ab2,50,74,178 -violet_color_wheel,"Violet (Color Wheel)",#7f00ff,127,0,255 -violet_ryb,"Violet (Ryb)",#8601af,134,1,175 -violet_web,"Violet (Web)",#ee82ee,238,130,238 -viridian,Viridian,#40826d,64,130,109 -vivid_auburn,"Vivid Auburn",#922724,146,39,36 -vivid_burgundy,"Vivid Burgundy",#9f1d35,159,29,53 -vivid_cerise,"Vivid Cerise",#da1d81,218,29,129 -vivid_tangerine,"Vivid Tangerine",#ffa089,255,160,137 -vivid_violet,"Vivid Violet",#9f00ff,159,0,255 -warm_black,"Warm Black",#004242,0,66,66 -waterspout,Waterspout,#a4f4f9,164,244,249 -wenge,Wenge,#645452,100,84,82 -wheat,Wheat,#f5deb3,245,222,179 -white,White,#fff,255,255,255 -white_smoke,"White Smoke",#f5f5f5,245,245,245 -wild_blue_yonder,"Wild Blue Yonder",#a2add0,162,173,208 -wild_strawberry,"Wild Strawberry",#ff43a4,255,67,164 -wild_watermelon,"Wild Watermelon",#fc6c85,252,108,133 -wine,Wine,#722f37,114,47,55 -wine_dregs,"Wine Dregs",#673147,103,49,71 -wisteria,Wisteria,#c9a0dc,201,160,220 -wood_brown,"Wood Brown",#c19a6b,193,154,107 -xanadu,Xanadu,#738678,115,134,120 -yale_blue,"Yale Blue",#0f4d92,15,77,146 -yellow,Yellow,#ff0,255,255,0 -yellow_green,Yellow-Green,#9acd32,154,205,50 -yellow_munsell,"Yellow (Munsell)",#efcc00,239,204,0 -yellow_ncs,"Yellow (Ncs)",#ffd300,255,211,0 -yellow_orange,"Yellow Orange",#ffae42,255,174,66 -yellow_process,"Yellow (Process)",#ffef00,255,239,0 -yellow_ryb,"Yellow (Ryb)",#fefe33,254,254,51 -zaffre,Zaffre,#0014a8,0,20,168 -zinnwaldite_brown,"Zinnwaldite Brown",#2c1608,44,22,8 diff --git a/skimage/novice/make_colors.py b/skimage/novice/make_colors.py deleted file mode 100644 index 2c14063d..00000000 --- a/skimage/novice/make_colors.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/python -import argparse, csv - -# Imports color names from a CSV file (colors.csv) and outputs a Python file -# with color name definitions (colors.py). - -def download_colors(path): - import urllib2, re - from bs4 import BeautifulSoup - - # All colors seem to be on this page - url = "http://en.wikipedia.org/wiki/List_of_colors:_A-M" - request = urllib2.Request(url) - opener = urllib2.build_opener() - request.add_header("User-Agent", "Mozilla/5.0") - html = opener.open(request).read() - - # Find first table with "Color names" caption - soup = BeautifulSoup(html, "lxml") - color_table = [t for t in soup.findAll("table") if t.find("caption") is not None - and t.find("caption").string == "Color names"][0] - - with open(path, "w") as out_file: - writer = csv.writer(out_file) - - # Each table row has the color name in a th and the hex - # color in the second td cell. - for row in color_table.findAll("tr"): - th = row.find("th") - cells = row.findAll("td") - if th is None or len(cells) < 2: - continue - - name = th.string.encode("ascii", "ignore") - - # Strip parens and replace non-alphanumeric characters with underscores - id_name = re.sub("[^a-zA-Z0-9]", "_", name.lower().replace("(", "").replace(")", "")) - hex_str = cells[1].string.encode("ascii", "ignore") - r, g, b = (int(hex_str[1:3], 16), int(hex_str[3:5], 16), int(hex_str[5:7], 16)) - - writer.writerow((id_name, name, hex_str, str(r), str(g), str(b))) - -# -------------------------------------------------- - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("--input", "-i", type=str, default="colors.csv", help="Input file (CSV)") - parser.add_argument("--output", "-o", type=str, default="colors.py", help="Output file (Python)") - parser.add_argument("--download", "-d", action="store_true", help="Download from Wikipedia") - args = parser.parse_args() - - if args.download: - download_colors(args.input) - - with open(args.input, "r") as input_file: - with open(args.output, "w") as output_file: - for row in csv.reader(input_file): - name = row[0].upper() - rgb = (int(row[-3]), int(row[-2]), int(row[-1])) - output_file.write("{0} = {1}\n".format(name, rgb)) From e86b0a161c0f204e00a45e046e5dc177ad7a881d Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Tue, 2 Jul 2013 23:22:02 -0500 Subject: [PATCH 09/51] Change inflate/inflation to rescale/scale. --- skimage/novice/novice.py | 45 +++++++++-------------------- skimage/novice/tests/test_novice.py | 2 +- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/skimage/novice/novice.py b/skimage/novice/novice.py index 067d9379..089d531e 100644 --- a/skimage/novice/novice.py +++ b/skimage/novice/novice.py @@ -327,7 +327,7 @@ class Picture(object): # Common setup. self._modified = False - self._inflation = 1 + self.scale = 1 @staticmethod def from_path(path): @@ -395,7 +395,7 @@ class Picture(object): Path to save the picture (with file extension). """ - io.imsave(path, self._inflate(self._image)) + io.imsave(path, self._rescale(self._image)) self._modified = False self._path = os.path.abspath(path) self._format = imghdr.what(path) @@ -454,33 +454,17 @@ class Picture(object): def height(self, value): self.size = (self.width, value) - @property - def inflation(self): - """The inflation factor.""" - return self._inflation - - @inflation.setter - def inflation(self, value): - try: - value = int(value) - if value < 1: - raise ValueError() - self._inflation = value - except ValueError: - msg = "Expected inflation factor to be an integer greater than one" - raise ValueError(msg) - def _repr_html_(self): - return io.Image(self._inflate(self._image)) + return io.Image(self._rescale(self._image)) def _repr_png_(self): - return io.Image(self._inflate(self._image)) + return io.Image(self._rescale(self._image)) def show(self): """Displays the image in a separate window. """ - io.imshow(self._inflate(self._image)) + io.imshow(self._rescale(self._image)) def _makepixel(self, xy): """ Creates a Pixel object for a given x, y location. @@ -495,22 +479,19 @@ class Picture(object): rgb = self._image[self.height - xy[1] - 1, xy[0]] return Pixel(self, self._image, xy[0], xy[1], rgb) - def _inflate(self, img): - """Inflates image according to inflation factor. + def _rescale(self, image): + """Inflates image according to scale factor. Parameters ---------- - img : array - Raw RGB image data to inflate using nearest neighbor algorithm. + image : array + Raw RGB image data to rescale using nearest neighbor algorithm. """ - if self._inflation == 1: - return img - - # skimage dimensions are flipped: y, x - return img_as_ubyte(resize(img, - (self.height * self._inflation, - self.width * self._inflation), order=0)) + if self.scale == 1: + return image + new_size = (self.height * self.scale, self.width * self.scale) + return img_as_ubyte(resize(image, new_size, order=0)) def __iter__(self): """Iterates over all pixels in the image.""" diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 737554a2..f039d9b2 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -18,7 +18,7 @@ def test_pic_info(): assert_equal(pic.width, 665) assert_equal(pic.height, 500) assert_equal(pic.modified, False) - assert_equal(pic.inflation, 1) + assert_equal(pic.scale, 1) def test_pixel_iteration(): From 2cf9466e9ea47462935c1b2f18404e2fceb7b417 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Tue, 2 Jul 2013 23:43:22 -0500 Subject: [PATCH 10/51] Clean up docstrings. __getitem__/__setitem__ docstrings aren't typically displayed so they're unnecessary. Move and fix doctests as well. --- skimage/novice/novice.py | 66 +++++++++++----------------------------- 1 file changed, 18 insertions(+), 48 deletions(-) diff --git a/skimage/novice/novice.py b/skimage/novice/novice.py index 089d531e..04a2d8ba 100644 --- a/skimage/novice/novice.py +++ b/skimage/novice/novice.py @@ -278,20 +278,33 @@ class Picture(object): Examples -------- Load an image from a file - - >>> pic = Picture(path="/path/to/image/file.png") + >>> from skimage import novice + >>> from skimage import data + >>> picture = novice.open(data.data_dir + '/elephant.png') Create a blank 100 pixel wide, 200 pixel tall white image - >>> pic = Picture(size=(100, 200), color=(255, 255, 255)) Use numpy to make an RGB byte array (shape is height x width x 3) - >>> import numpy as np - >>> data = np.zeros(shape=(200, 100, 3), dtype=np.int8) + >>> data = np.zeros(shape=(200, 100, 3), dtype=np.uint8) >>> data[:, :, 0] = 255 # Set red component to maximum >>> pic = Picture(image=data) + Get the bottom-left pixel + >>> pic[0, 0] + Pixel (red: 255, green: 0, blue: 0) + + Get the top row of the picture + >>> pic[:, pic.height-1] + PixelGroup (100 pixels) + + Set the bottom-left pixel to black + >>> pic[0, 0] = (0, 0, 0) + + Set the top row to red + >>> pic[:, pic.height-1] = (255, 0, 0) + """ def __init__(self, path=None, size=None, color=None, image=None): # Can only provide either path or size, but not both. @@ -500,29 +513,6 @@ class Picture(object): yield self._makepixel((x, y)) def __getitem__(self, key): - """Gets pixels using 2D int or slice notations. - - Parameters - ---------- - key : tuple - Horizontal and vertical coordinates or slices. - - Returns - ------- - p: Pixel or PixelGroup - Single pixel for coordinates or PixelGroup for slice. - - Examples - -------- - Get the bottom-left pixel - - >>> pic[0, 0] - - Get the top row of the picture - - >>> pic[:, pic.height-1] - - """ if isinstance(key, tuple) and len(key) == 2: if isinstance(key[0], int) and isinstance(key[1], int): if key[0] < 0 or key[1] < 0: @@ -535,26 +525,6 @@ class Picture(object): raise TypeError("Invalid key type") def __setitem__(self, key, value): - """Sets pixel values using 2D int or slice notations. - - Parameters - ---------- - key : tuple - Horizontal and vertical coordinates or slices. - value : tuple - RGB tuple with red, green, and blue components [0-255] - - Examples - -------- - Set the bottom-left pixel to black - - >>> pic[0, 0] = (0, 0, 0) - - Set the top row to red - - >>> pic[:, pic.height-1] = (255, 0, 0) - - """ if isinstance(key, tuple) and len(key) == 2: if isinstance(value, tuple): self[key[0], key[1]].rgb = value From c881cf32e68affd2201d867f516c8fe5fa1459ec Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Tue, 2 Jul 2013 23:46:49 -0500 Subject: [PATCH 11/51] Remove unnecessary functions. --- skimage/novice/__init__.py | 2 +- skimage/novice/novice.py | 18 +----------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/skimage/novice/__init__.py b/skimage/novice/__init__.py index 3256e22b..2ce10777 100644 --- a/skimage/novice/__init__.py +++ b/skimage/novice/__init__.py @@ -71,4 +71,4 @@ False """ from . import colors -from .novice import Picture, open, new, copy +from .novice import Picture, open diff --git a/skimage/novice/novice.py b/skimage/novice/novice.py index 04a2d8ba..5757002a 100644 --- a/skimage/novice/novice.py +++ b/skimage/novice/novice.py @@ -8,25 +8,9 @@ from skimage.transform import resize def open(path): - """ - Creates a new Picture object from the given image path - """ + """Return Picture object from the given image path.""" return Picture(path=os.path.abspath(path)) -def new(size, color=None): - """ - Create a new RGB picture of the given size, initialized to the - given color or to black if none is provided. - """ - return Picture(size=size, color=color) - -def copy(image): - """ - Creates a Picture using the supplied image data - (e.g., skimage.data.elephant()). - """ - return Picture(image=image) - class Pixel(object): """A single pixel in a Picture. From 896e471a123567efa2337bfb10d0f2c0e20a4ade Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Wed, 3 Jul 2013 00:19:07 -0500 Subject: [PATCH 12/51] Fix `modified` flag behavior --- skimage/novice/novice.py | 18 +++++++++--------- skimage/novice/tests/test_novice.py | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/skimage/novice/novice.py b/skimage/novice/novice.py index 5757002a..37eda63c 100644 --- a/skimage/novice/novice.py +++ b/skimage/novice/novice.py @@ -111,13 +111,9 @@ class Pixel(object): NOTE: Using Cartesian coordinate system! """ - # skimage dimensions are flipped: y, x - self._image[self._picture.height - self._y - 1, self._x] = \ - (self.red, self.green, self.blue) - - # Modified pictures lose their paths - self._picture._picture_path = None - self._picture._picture_modified = True + row = self._picture.height - self._y - 1 + self._picture._image[row, self._x] = self.rgb + self._picture._image_modified() def __repr__(self): args = self.red, self.green, self.blue @@ -407,6 +403,10 @@ class Picture(object): """True if the picture has changed.""" return self._modified + def _image_modified(self): + self._modified = True + self._path = None + @property def format(self): """The image format of the picture.""" @@ -427,8 +427,7 @@ class Picture(object): self._image = img_as_ubyte(resize(self._image, (int(value[1]), int(value[0])), order=0)) - self._modified = True - self._path = None + self._image_modified() except TypeError: msg = "Expected (width, height), but got {0} instead!" raise TypeError(msg.format(value)) @@ -519,6 +518,7 @@ class Picture(object): raise TypeError("Invalid value type") else: raise TypeError("Invalid key type") + self._image_modified() def __repr__(self): args = self.format, self.path, self.modified diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index f039d9b2..19a2d34c 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -1,6 +1,7 @@ import os import tempfile +import numpy as np from numpy.testing import assert_equal, assert_raises from skimage import novice from skimage import data_dir @@ -50,6 +51,29 @@ def test_modify(): assert_equal(pic.modified, True) assert_equal(pic.path, None) + +def test_modified_on_set(): + pic = novice.Picture(SMALL_IMAGE_PATH) + pic[0, 0] = (1, 1, 1) + assert_equal(pic.modified, True) + assert_equal(pic.path, None) + + +def test_modified_on_set_pixel(): + data = np.zeros(shape=(10, 5, 3), dtype=np.uint8) + pic = novice.Picture(image=data) + + pixel = pic[0, 0] + pixel.green = 1 + assert_equal(pic.modified, True) + + +def test_update_on_save(): + pic = novice.Picture(image=np.zeros((3, 3))) + pic.size = (6, 6) + assert_equal(pic.modified, True) + assert_equal(pic.path, None) + with tempfile.NamedTemporaryFile(suffix=".jpg") as tmp: pic.save(tmp.name) From 06636266675b8c9e17214edcc48e551d969bce9e Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 5 Jul 2013 21:49:31 -0500 Subject: [PATCH 13/51] Clean up color_dict definition --- skimage/color/colorlabel.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/skimage/color/colorlabel.py b/skimage/color/colorlabel.py index 8d7787aa..52b12dfb 100644 --- a/skimage/color/colorlabel.py +++ b/skimage/color/colorlabel.py @@ -17,7 +17,8 @@ DEFAULT_COLORS = ('red', 'blue', 'yellow', 'magenta', 'green', 'indigo', 'darkorange', 'cyan', 'pink', 'yellowgreen') -color_dict = rgb_colors.__dict__ +color_dict = dict((k, v) for k, v in rgb_colors.__dict__.iteritems() + if isinstance(v, tuple)) def _rgb_vector(color): From 266c28ba6baa76287e07096178fcb54fedd27527 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 5 Jul 2013 22:21:32 -0500 Subject: [PATCH 14/51] Reuse colors from skimage.color. This change greatly reduces the number of available colors, which is probably a good thing. --- skimage/novice/__init__.py | 3 +- skimage/novice/colors.py | 865 ------------------------------------- skimage/novice/novice.py | 10 + 3 files changed, 11 insertions(+), 867 deletions(-) delete mode 100644 skimage/novice/colors.py diff --git a/skimage/novice/__init__.py b/skimage/novice/__init__.py index 2ce10777..fad92768 100644 --- a/skimage/novice/__init__.py +++ b/skimage/novice/__init__.py @@ -70,5 +70,4 @@ False """ -from . import colors -from .novice import Picture, open +from .novice import Picture, open, colors, color_dict diff --git a/skimage/novice/colors.py b/skimage/novice/colors.py deleted file mode 100644 index 6ff98a85..00000000 --- a/skimage/novice/colors.py +++ /dev/null @@ -1,865 +0,0 @@ -AIR_FORCE_BLUE_RAF = (93, 138, 168) -AIR_FORCE_BLUE_USAF = (0, 48, 143) -AIR_SUPERIORITY_BLUE = (114, 160, 193) -ALABAMA_CRIMSON = (163, 38, 56) -ALICE_BLUE = (240, 248, 255) -ALIZARIN_CRIMSON = (227, 38, 54) -ALLOY_ORANGE = (196, 98, 16) -ALMOND = (239, 222, 205) -AMARANTH = (229, 43, 80) -AMBER = (255, 191, 0) -AMBER_SAE_ECE = (255, 126, 0) -AMERICAN_ROSE = (255, 3, 62) -AMETHYST = (153, 102, 204) -ANDROID_GREEN = (164, 198, 57) -ANTI_FLASH_WHITE = (242, 243, 244) -ANTIQUE_BRASS = (205, 149, 117) -ANTIQUE_FUCHSIA = (145, 92, 131) -ANTIQUE_RUBY = (132, 27, 45) -ANTIQUE_WHITE = (250, 235, 215) -AO_ENGLISH = (0, 128, 0) -APPLE_GREEN = (141, 182, 0) -APRICOT = (251, 206, 177) -AQUA = (0, 255, 255) -AQUAMARINE = (127, 255, 212) -ARMY_GREEN = (75, 83, 32) -ARSENIC = (59, 68, 75) -ARYLIDE_YELLOW = (233, 214, 107) -ASH_GREY = (178, 190, 181) -ASPARAGUS = (135, 169, 107) -ATOMIC_TANGERINE = (255, 153, 102) -AUBURN = (165, 42, 42) -AUREOLIN = (253, 238, 0) -AUROMETALSAURUS = (110, 127, 128) -AVOCADO = (86, 130, 3) -AZURE = (0, 127, 255) -AZURE_MIST_WEB = (240, 255, 255) -BABY_BLUE = (137, 207, 240) -BABY_BLUE_EYES = (161, 202, 241) -BABY_PINK = (244, 194, 194) -BALL_BLUE = (33, 171, 205) -BANANA_MANIA = (250, 231, 181) -BANANA_YELLOW = (255, 225, 53) -BARN_RED = (124, 10, 2) -BATTLESHIP_GREY = (132, 132, 130) -BAZAAR = (152, 119, 123) -BEAU_BLUE = (188, 212, 230) -BEAVER = (159, 129, 112) -BEIGE = (245, 245, 220) -BIG_DIP_O_RUBY = (156, 37, 66) -BISQUE = (255, 228, 196) -BISTRE = (61, 43, 31) -BITTERSWEET = (254, 111, 94) -BITTERSWEET_SHIMMER = (191, 79, 81) -BLACK = (0, 0, 0) -BLACK_BEAN = (61, 12, 2) -BLACK_LEATHER_JACKET = (37, 53, 41) -BLACK_OLIVE = (59, 60, 54) -BLANCHED_ALMOND = (255, 235, 205) -BLAST_OFF_BRONZE = (165, 113, 100) -BLEU_DE_FRANCE = (49, 140, 231) -BLIZZARD_BLUE = (172, 229, 238) -BLOND = (250, 240, 190) -BLUE = (0, 0, 255) -BLUE_BELL = (162, 162, 208) -BLUE_CRAYOLA = (31, 117, 254) -BLUE_GRAY = (102, 153, 204) -BLUE_GREEN = (13, 152, 186) -BLUE_MUNSELL = (0, 147, 175) -BLUE_NCS = (0, 135, 189) -BLUE_PIGMENT = (51, 51, 153) -BLUE_RYB = (2, 71, 254) -BLUE_SAPPHIRE = (18, 97, 128) -BLUE_VIOLET = (138, 43, 226) -BLUSH = (222, 93, 131) -BOLE = (121, 68, 59) -BONDI_BLUE = (0, 149, 182) -BONE = (227, 218, 201) -BOSTON_UNIVERSITY_RED = (204, 0, 0) -BOTTLE_GREEN = (0, 106, 78) -BOYSENBERRY = (135, 50, 96) -BRANDEIS_BLUE = (0, 112, 255) -BRASS = (181, 166, 66) -BRICK_RED = (203, 65, 84) -BRIGHT_CERULEAN = (29, 172, 214) -BRIGHT_GREEN = (102, 255, 0) -BRIGHT_LAVENDER = (191, 148, 228) -BRIGHT_MAROON = (195, 33, 72) -BRIGHT_PINK = (255, 0, 127) -BRIGHT_TURQUOISE = (8, 232, 222) -BRIGHT_UBE = (209, 159, 232) -BRILLIANT_LAVENDER = (244, 187, 255) -BRILLIANT_ROSE = (255, 85, 163) -BRINK_PINK = (251, 96, 127) -BRITISH_RACING_GREEN = (0, 66, 37) -BRONZE = (205, 127, 50) -BROWN_TRADITIONAL = (150, 75, 0) -BROWN_WEB = (165, 42, 42) -BUBBLE_GUM = (255, 193, 204) -BUBBLES = (231, 254, 255) -BUFF = (240, 220, 130) -BULGARIAN_ROSE = (72, 6, 7) -BURGUNDY = (128, 0, 32) -BURLYWOOD = (222, 184, 135) -BURNT_ORANGE = (204, 85, 0) -BURNT_SIENNA = (233, 116, 81) -BURNT_UMBER = (138, 51, 36) -BYZANTINE = (189, 51, 164) -BYZANTIUM = (112, 41, 99) -CADET = (83, 104, 114) -CADET_BLUE = (95, 158, 160) -CADET_GREY = (145, 163, 176) -CADMIUM_GREEN = (0, 107, 60) -CADMIUM_ORANGE = (237, 135, 45) -CADMIUM_RED = (227, 0, 34) -CADMIUM_YELLOW = (255, 246, 0) -CAF_AU_LAIT = (166, 123, 91) -CAF_NOIR = (75, 54, 33) -CAL_POLY_GREEN = (30, 77, 43) -CAMBRIDGE_BLUE = (163, 193, 173) -CAMEL = (193, 154, 107) -CAMEO_PINK = (239, 187, 204) -CAMOUFLAGE_GREEN = (120, 134, 107) -CANARY_YELLOW = (255, 239, 0) -CANDY_APPLE_RED = (255, 8, 0) -CANDY_PINK = (228, 113, 122) -CAPRI = (0, 191, 255) -CAPUT_MORTUUM = (89, 39, 32) -CARDINAL = (196, 30, 58) -CARIBBEAN_GREEN = (0, 204, 153) -CARMINE = (150, 0, 24) -CARMINE_M_P = (215, 0, 64) -CARMINE_PINK = (235, 76, 66) -CARMINE_RED = (255, 0, 56) -CARNATION_PINK = (255, 166, 201) -CARNELIAN = (179, 27, 27) -CAROLINA_BLUE = (153, 186, 221) -CARROT_ORANGE = (237, 145, 33) -CATALINA_BLUE = (6, 42, 120) -CEIL = (146, 161, 207) -CELADON = (172, 225, 175) -CELADON_BLUE = (0, 123, 167) -CELADON_GREEN = (47, 132, 124) -CELESTE_COLOUR = (178, 255, 255) -CELESTIAL_BLUE = (73, 151, 208) -CERISE = (222, 49, 99) -CERISE_PINK = (236, 59, 131) -CERULEAN = (0, 123, 167) -CERULEAN_BLUE = (42, 82, 190) -CERULEAN_FROST = (109, 155, 195) -CG_BLUE = (0, 122, 165) -CG_RED = (224, 60, 49) -CHAMOISEE = (160, 120, 90) -CHAMPAGNE = (250, 214, 165) -CHARCOAL = (54, 69, 79) -CHARM_PINK = (230, 143, 172) -CHARTREUSE_TRADITIONAL = (223, 255, 0) -CHARTREUSE_WEB = (127, 255, 0) -CHERRY = (222, 49, 99) -CHERRY_BLOSSOM_PINK = (255, 183, 197) -CHESTNUT = (205, 92, 92) -CHINA_PINK = (222, 111, 161) -CHINA_ROSE = (168, 81, 110) -CHINESE_RED = (170, 56, 30) -CHOCOLATE_TRADITIONAL = (123, 63, 0) -CHOCOLATE_WEB = (210, 105, 30) -CHROME_YELLOW = (255, 167, 0) -CINEREOUS = (152, 129, 123) -CINNABAR = (227, 66, 52) -CINNAMON = (210, 105, 30) -CITRINE = (228, 208, 10) -CLASSIC_ROSE = (251, 204, 231) -COBALT = (0, 71, 171) -COCOA_BROWN = (210, 105, 30) -COFFEE = (111, 78, 55) -COLUMBIA_BLUE = (155, 221, 255) -CONGO_PINK = (248, 131, 121) -COOL_BLACK = (0, 46, 99) -COOL_GREY = (140, 146, 172) -COPPER = (184, 115, 51) -COPPER_CRAYOLA = (218, 138, 103) -COPPER_PENNY = (173, 111, 105) -COPPER_RED = (203, 109, 81) -COPPER_ROSE = (153, 102, 102) -COQUELICOT = (255, 56, 0) -CORAL = (255, 127, 80) -CORAL_PINK = (248, 131, 121) -CORAL_RED = (255, 64, 64) -CORDOVAN = (137, 63, 69) -CORN = (251, 236, 93) -CORNELL_RED = (179, 27, 27) -CORNFLOWER_BLUE = (100, 149, 237) -CORNSILK = (255, 248, 220) -COSMIC_LATTE = (255, 248, 231) -COTTON_CANDY = (255, 188, 217) -CREAM = (255, 253, 208) -CRIMSON = (220, 20, 60) -CRIMSON_GLORY = (190, 0, 50) -CYAN = (0, 255, 255) -CYAN_PROCESS = (0, 183, 235) -DAFFODIL = (255, 255, 49) -DANDELION = (240, 225, 48) -DARK_BLUE = (0, 0, 139) -DARK_BROWN = (101, 67, 33) -DARK_BYZANTIUM = (93, 57, 84) -DARK_CANDY_APPLE_RED = (164, 0, 0) -DARK_CERULEAN = (8, 69, 126) -DARK_CHESTNUT = (152, 105, 96) -DARK_CORAL = (205, 91, 69) -DARK_CYAN = (0, 139, 139) -DARK_ELECTRIC_BLUE = (83, 104, 120) -DARK_GOLDENROD = (184, 134, 11) -DARK_GRAY = (169, 169, 169) -DARK_GREEN = (1, 50, 32) -DARK_IMPERIAL_BLUE = (0, 65, 106) -DARK_JUNGLE_GREEN = (26, 36, 33) -DARK_KHAKI = (189, 183, 107) -DARK_LAVA = (72, 60, 50) -DARK_LAVENDER = (115, 79, 150) -DARK_MAGENTA = (139, 0, 139) -DARK_MIDNIGHT_BLUE = (0, 51, 102) -DARK_OLIVE_GREEN = (85, 107, 47) -DARK_ORANGE = (255, 140, 0) -DARK_ORCHID = (153, 50, 204) -DARK_PASTEL_BLUE = (119, 158, 203) -DARK_PASTEL_GREEN = (3, 192, 60) -DARK_PASTEL_PURPLE = (150, 111, 214) -DARK_PASTEL_RED = (194, 59, 34) -DARK_PINK = (231, 84, 128) -DARK_POWDER_BLUE = (0, 51, 153) -DARK_RASPBERRY = (135, 38, 87) -DARK_RED = (139, 0, 0) -DARK_SALMON = (233, 150, 122) -DARK_SCARLET = (86, 3, 25) -DARK_SEA_GREEN = (143, 188, 143) -DARK_SIENNA = (60, 20, 20) -DARK_SLATE_BLUE = (72, 61, 139) -DARK_SLATE_GRAY = (47, 79, 79) -DARK_SPRING_GREEN = (23, 114, 69) -DARK_TAN = (145, 129, 81) -DARK_TANGERINE = (255, 168, 18) -DARK_TAUPE = (72, 60, 50) -DARK_TERRA_COTTA = (204, 78, 92) -DARK_TURQUOISE = (0, 206, 209) -DARK_VIOLET = (148, 0, 211) -DARK_YELLOW = (155, 135, 12) -DARTMOUTH_GREEN = (0, 112, 60) -DAVY_S_GREY = (85, 85, 85) -DEBIAN_RED = (215, 10, 83) -DEEP_CARMINE = (169, 32, 62) -DEEP_CARMINE_PINK = (239, 48, 56) -DEEP_CARROT_ORANGE = (233, 105, 44) -DEEP_CERISE = (218, 50, 135) -DEEP_CHAMPAGNE = (250, 214, 165) -DEEP_CHESTNUT = (185, 78, 72) -DEEP_COFFEE = (112, 66, 65) -DEEP_FUCHSIA = (193, 84, 193) -DEEP_JUNGLE_GREEN = (0, 75, 73) -DEEP_LILAC = (153, 85, 187) -DEEP_MAGENTA = (204, 0, 204) -DEEP_PEACH = (255, 203, 164) -DEEP_PINK = (255, 20, 147) -DEEP_RUBY = (132, 63, 91) -DEEP_SAFFRON = (255, 153, 51) -DEEP_SKY_BLUE = (0, 191, 255) -DEEP_TUSCAN_RED = (102, 66, 77) -DENIM = (21, 96, 189) -DESERT = (193, 154, 107) -DESERT_SAND = (237, 201, 175) -DIM_GRAY = (105, 105, 105) -DODGER_BLUE = (30, 144, 255) -DOGWOOD_ROSE = (215, 24, 104) -DOLLAR_BILL = (133, 187, 101) -DRAB = (150, 113, 23) -DUKE_BLUE = (0, 0, 156) -EARTH_YELLOW = (225, 169, 95) -EBONY = (85, 93, 80) -ECRU = (194, 178, 128) -EGGPLANT = (97, 64, 81) -EGGSHELL = (240, 234, 214) -EGYPTIAN_BLUE = (16, 52, 166) -ELECTRIC_BLUE = (125, 249, 255) -ELECTRIC_CRIMSON = (255, 0, 63) -ELECTRIC_CYAN = (0, 255, 255) -ELECTRIC_GREEN = (0, 255, 0) -ELECTRIC_INDIGO = (111, 0, 255) -ELECTRIC_LAVENDER = (244, 187, 255) -ELECTRIC_LIME = (204, 255, 0) -ELECTRIC_PURPLE = (191, 0, 255) -ELECTRIC_ULTRAMARINE = (63, 0, 255) -ELECTRIC_VIOLET = (143, 0, 255) -ELECTRIC_YELLOW = (255, 255, 0) -EMERALD = (80, 200, 120) -ENGLISH_LAVENDER = (180, 131, 149) -ETON_BLUE = (150, 200, 162) -FALLOW = (193, 154, 107) -FALU_RED = (128, 24, 24) -FANDANGO = (181, 51, 137) -FASHION_FUCHSIA = (244, 0, 161) -FAWN = (229, 170, 112) -FELDGRAU = (77, 93, 83) -FERN_GREEN = (79, 121, 66) -FERRARI_RED = (255, 40, 0) -FIELD_DRAB = (108, 84, 30) -FIRE_ENGINE_RED = (206, 32, 41) -FIREBRICK = (178, 34, 34) -FLAME = (226, 88, 34) -FLAMINGO_PINK = (252, 142, 172) -FLAVESCENT = (247, 233, 142) -FLAX = (238, 220, 130) -FLORAL_WHITE = (255, 250, 240) -FLUORESCENT_ORANGE = (255, 191, 0) -FLUORESCENT_PINK = (255, 20, 147) -FLUORESCENT_YELLOW = (204, 255, 0) -FOLLY = (255, 0, 79) -FOREST_GREEN_TRADITIONAL = (1, 68, 33) -FOREST_GREEN_WEB = (34, 139, 34) -FRENCH_BEIGE = (166, 123, 91) -FRENCH_BLUE = (0, 114, 187) -FRENCH_LILAC = (134, 96, 142) -FRENCH_LIME = (204, 255, 0) -FRENCH_RASPBERRY = (199, 44, 72) -FRENCH_ROSE = (246, 74, 138) -FUCHSIA = (255, 0, 255) -FUCHSIA_CRAYOLA = (193, 84, 193) -FUCHSIA_PINK = (255, 119, 255) -FUCHSIA_ROSE = (199, 67, 117) -FULVOUS = (228, 132, 0) -FUZZY_WUZZY = (204, 102, 102) -GAINSBORO = (220, 220, 220) -GAMBOGE = (228, 155, 15) -GHOST_WHITE = (248, 248, 255) -GINGER = (176, 101, 0) -GLAUCOUS = (96, 130, 182) -GLITTER = (230, 232, 250) -GOLD_METALLIC = (212, 175, 55) -GOLD_WEB_GOLDEN = (255, 215, 0) -GOLDEN_BROWN = (153, 101, 21) -GOLDEN_POPPY = (252, 194, 0) -GOLDEN_YELLOW = (255, 223, 0) -GOLDENROD = (218, 165, 32) -GRANNY_SMITH_APPLE = (168, 228, 160) -GRAY = (128, 128, 128) -GRAY_ASPARAGUS = (70, 89, 69) -GRAY_HTML_CSS_GRAY = (128, 128, 128) -GRAY_X11_GRAY = (190, 190, 190) -GREEN = (0, 255, 0) -GREEN_CRAYOLA = (28, 172, 120) -GREEN_HTML_CSS_GREEN = (0, 128, 0) -GREEN_MUNSELL = (0, 168, 119) -GREEN_NCS = (0, 159, 107) -GREEN_PIGMENT = (0, 165, 80) -GREEN_RYB = (102, 176, 50) -GREEN_YELLOW = (173, 255, 47) -GRULLO = (169, 154, 134) -GUPPIE_GREEN = (0, 255, 127) -HALAY_BE = (102, 56, 84) -HAN_BLUE = (68, 108, 207) -HAN_PURPLE = (82, 24, 250) -HANSA_YELLOW = (233, 214, 107) -HARLEQUIN = (63, 255, 0) -HARVARD_CRIMSON = (201, 0, 22) -HARVEST_GOLD = (218, 145, 0) -HEART_GOLD = (128, 128, 0) -HELIOTROPE = (223, 115, 255) -HOLLYWOOD_CERISE = (244, 0, 161) -HONEYDEW = (240, 255, 240) -HONOLULU_BLUE = (0, 127, 191) -HOOKER_S_GREEN = (73, 121, 107) -HOT_MAGENTA = (255, 29, 206) -HOT_PINK = (255, 105, 180) -HUNTER_GREEN = (53, 94, 59) -ICEBERG = (113, 166, 210) -ICTERINE = (252, 247, 94) -IMPERIAL_BLUE = (0, 35, 149) -INCHWORM = (178, 236, 93) -INDIA_GREEN = (19, 136, 8) -INDIAN_RED = (205, 92, 92) -INDIAN_YELLOW = (227, 168, 87) -INDIGO = (111, 0, 255) -INDIGO_DYE = (0, 65, 106) -INDIGO_WEB = (75, 0, 130) -INTERNATIONAL_KLEIN_BLUE = (0, 47, 167) -INTERNATIONAL_ORANGE_AEROSPACE = (255, 79, 0) -INTERNATIONAL_ORANGE_ENGINEERING = (186, 22, 12) -INTERNATIONAL_ORANGE_GOLDEN_GATE_BRIDGE = (192, 54, 44) -IRIS = (90, 79, 207) -ISABELLINE = (244, 240, 236) -ISLAMIC_GREEN = (0, 144, 0) -IVORY = (255, 255, 240) -JADE = (0, 168, 107) -JASMINE = (248, 222, 126) -JASPER = (215, 59, 62) -JAZZBERRY_JAM = (165, 11, 94) -JET = (52, 52, 52) -JONQUIL = (250, 218, 94) -JUNE_BUD = (189, 218, 87) -JUNGLE_GREEN = (41, 171, 135) -KELLY_GREEN = (76, 187, 23) -KENYAN_COPPER = (124, 28, 5) -KHAKI_HTML_CSS_KHAKI = (195, 176, 145) -KHAKI_X11_LIGHT_KHAKI = (240, 230, 140) -KU_CRIMSON = (232, 0, 13) -LA_SALLE_GREEN = (8, 120, 48) -LANGUID_LAVENDER = (214, 202, 221) -LAPIS_LAZULI = (38, 97, 156) -LASER_LEMON = (254, 254, 34) -LAUREL_GREEN = (169, 186, 157) -LAVA = (207, 16, 32) -LAVENDER_BLUE = (204, 204, 255) -LAVENDER_BLUSH = (255, 240, 245) -LAVENDER_FLORAL = (181, 126, 220) -LAVENDER_GRAY = (196, 195, 208) -LAVENDER_INDIGO = (148, 87, 235) -LAVENDER_MAGENTA = (238, 130, 238) -LAVENDER_MIST = (230, 230, 250) -LAVENDER_PINK = (251, 174, 210) -LAVENDER_PURPLE = (150, 123, 182) -LAVENDER_ROSE = (251, 160, 227) -LAVENDER_WEB = (230, 230, 250) -LAWN_GREEN = (124, 252, 0) -LEMON = (255, 247, 0) -LEMON_CHIFFON = (255, 250, 205) -LEMON_LIME = (227, 255, 0) -LICORICE = (26, 17, 16) -LIGHT_APRICOT = (253, 213, 177) -LIGHT_BLUE = (173, 216, 230) -LIGHT_BROWN = (181, 101, 29) -LIGHT_CARMINE_PINK = (230, 103, 113) -LIGHT_CORAL = (240, 128, 128) -LIGHT_CORNFLOWER_BLUE = (147, 204, 234) -LIGHT_CRIMSON = (245, 105, 145) -LIGHT_CYAN = (224, 255, 255) -LIGHT_FUCHSIA_PINK = (249, 132, 239) -LIGHT_GOLDENROD_YELLOW = (250, 250, 210) -LIGHT_GRAY = (211, 211, 211) -LIGHT_GREEN = (144, 238, 144) -LIGHT_KHAKI = (240, 230, 140) -LIGHT_PASTEL_PURPLE = (177, 156, 217) -LIGHT_PINK = (255, 182, 193) -LIGHT_RED_OCHRE = (233, 116, 81) -LIGHT_SALMON = (255, 160, 122) -LIGHT_SALMON_PINK = (255, 153, 153) -LIGHT_SEA_GREEN = (32, 178, 170) -LIGHT_SKY_BLUE = (135, 206, 250) -LIGHT_SLATE_GRAY = (119, 136, 153) -LIGHT_TAUPE = (179, 139, 109) -LIGHT_THULIAN_PINK = (230, 143, 172) -LIGHT_YELLOW = (255, 255, 224) -LILAC = (200, 162, 200) -LIME = (191, 255, 0) -LIME_GREEN = (50, 205, 50) -LIME_WEB_X11_GREEN = (0, 255, 0) -LIMERICK = (157, 194, 9) -LINCOLN_GREEN = (25, 89, 5) -LINEN = (250, 240, 230) -LION = (193, 154, 107) -LITTLE_BOY_BLUE = (108, 160, 220) -LIVER = (83, 75, 79) -LUST = (230, 32, 32) -MAGENTA = (255, 0, 255) -MAGENTA_DYE = (202, 31, 123) -MAGENTA_PROCESS = (255, 0, 144) -MAGIC_MINT = (170, 240, 209) -MAGNOLIA = (248, 244, 255) -MAHOGANY = (192, 64, 0) -MAIZE = (251, 236, 93) -MAJORELLE_BLUE = (96, 80, 220) -MALACHITE = (11, 218, 81) -MANATEE = (151, 154, 170) -MANGO_TANGO = (255, 130, 67) -MANTIS = (116, 195, 101) -MARDI_GRAS = (136, 0, 133) -MAROON_CRAYOLA = (195, 33, 72) -MAROON_HTML_CSS = (128, 0, 0) -MAROON_X11 = (176, 48, 96) -MAUVE = (224, 176, 255) -MAUVE_TAUPE = (145, 95, 109) -MAUVELOUS = (239, 152, 170) -MAYA_BLUE = (115, 194, 251) -MEAT_BROWN = (229, 183, 59) -MEDIUM_AQUAMARINE = (102, 221, 170) -MEDIUM_BLUE = (0, 0, 205) -MEDIUM_CANDY_APPLE_RED = (226, 6, 44) -MEDIUM_CARMINE = (175, 64, 53) -MEDIUM_CHAMPAGNE = (243, 229, 171) -MEDIUM_ELECTRIC_BLUE = (3, 80, 150) -MEDIUM_JUNGLE_GREEN = (28, 53, 45) -MEDIUM_LAVENDER_MAGENTA = (221, 160, 221) -MEDIUM_ORCHID = (186, 85, 211) -MEDIUM_PERSIAN_BLUE = (0, 103, 165) -MEDIUM_PURPLE = (147, 112, 219) -MEDIUM_RED_VIOLET = (187, 51, 133) -MEDIUM_RUBY = (170, 64, 105) -MEDIUM_SEA_GREEN = (60, 179, 113) -MEDIUM_SLATE_BLUE = (123, 104, 238) -MEDIUM_SPRING_BUD = (201, 220, 135) -MEDIUM_SPRING_GREEN = (0, 250, 154) -MEDIUM_TAUPE = (103, 76, 71) -MEDIUM_TURQUOISE = (72, 209, 204) -MEDIUM_TUSCAN_RED = (121, 68, 59) -MEDIUM_VERMILION = (217, 96, 59) -MEDIUM_VIOLET_RED = (199, 21, 133) -MELLOW_APRICOT = (248, 184, 120) -MELLOW_YELLOW = (248, 222, 126) -MELON = (253, 188, 180) -MIDNIGHT_BLUE = (25, 25, 112) -MIDNIGHT_GREEN_EAGLE_GREEN = (0, 73, 83) -MIKADO_YELLOW = (255, 196, 12) -MINT = (62, 180, 137) -MINT_CREAM = (245, 255, 250) -MINT_GREEN = (152, 255, 152) -MISTY_ROSE = (255, 228, 225) -MOCCASIN = (250, 235, 215) -MODE_BEIGE = (150, 113, 23) -MOONSTONE_BLUE = (115, 169, 194) -MORDANT_RED_19 = (174, 12, 0) -MOSS_GREEN = (173, 223, 173) -MOUNTAIN_MEADOW = (48, 186, 143) -MOUNTBATTEN_PINK = (153, 122, 141) -MSU_GREEN = (24, 69, 59) -MULBERRY = (197, 75, 140) -MUSTARD = (255, 219, 88) -MYRTLE = (33, 66, 30) -NADESHIKO_PINK = (246, 173, 198) -NAPIER_GREEN = (42, 128, 0) -NAPLES_YELLOW = (250, 218, 94) -NAVAJO_WHITE = (255, 222, 173) -NAVY_BLUE = (0, 0, 128) -NEON_CARROT = (255, 163, 67) -NEON_FUCHSIA = (254, 65, 100) -NEON_GREEN = (57, 255, 20) -NEW_YORK_PINK = (215, 131, 127) -NON_PHOTO_BLUE = (164, 221, 237) -NORTH_TEXAS_GREEN = (5, 144, 51) -OCEAN_BOAT_BLUE = (0, 119, 190) -OCHRE = (204, 119, 34) -OFFICE_GREEN = (0, 128, 0) -OLD_GOLD = (207, 181, 59) -OLD_LACE = (253, 245, 230) -OLD_LAVENDER = (121, 104, 120) -OLD_MAUVE = (103, 49, 71) -OLD_ROSE = (192, 128, 129) -OLIVE = (128, 128, 0) -OLIVE_DRAB_7 = (60, 52, 31) -OLIVE_DRAB_WEB_OLIVE_DRAB_3 = (107, 142, 35) -OLIVINE = (154, 185, 115) -ONYX = (53, 56, 57) -OPERA_MAUVE = (183, 132, 167) -ORANGE = (255, 127, 0) -ORANGE_PEEL = (255, 159, 0) -ORANGE_RED = (255, 69, 0) -ORANGE_RYB = (251, 153, 2) -ORANGE_WEB_COLOR = (255, 165, 0) -ORCHID = (218, 112, 214) -OTTER_BROWN = (101, 67, 33) -OU_CRIMSON_RED = (153, 0, 0) -OUTER_SPACE = (65, 74, 76) -OUTRAGEOUS_ORANGE = (255, 110, 74) -OXFORD_BLUE = (0, 33, 71) -PAKISTAN_GREEN = (0, 102, 0) -PALATINATE_BLUE = (39, 59, 226) -PALATINATE_PURPLE = (104, 40, 96) -PALE_AQUA = (188, 212, 230) -PALE_BLUE = (175, 238, 238) -PALE_BROWN = (152, 118, 84) -PALE_CARMINE = (175, 64, 53) -PALE_CERULEAN = (155, 196, 226) -PALE_CHESTNUT = (221, 173, 175) -PALE_COPPER = (218, 138, 103) -PALE_CORNFLOWER_BLUE = (171, 205, 239) -PALE_GOLD = (230, 190, 138) -PALE_GOLDENROD = (238, 232, 170) -PALE_GREEN = (152, 251, 152) -PALE_LAVENDER = (220, 208, 255) -PALE_MAGENTA = (249, 132, 229) -PALE_PINK = (250, 218, 221) -PALE_PLUM = (221, 160, 221) -PALE_RED_VIOLET = (219, 112, 147) -PALE_ROBIN_EGG_BLUE = (150, 222, 209) -PALE_SILVER = (201, 192, 187) -PALE_SPRING_BUD = (236, 235, 189) -PALE_TAUPE = (188, 152, 126) -PALE_VIOLET_RED = (219, 112, 147) -PANSY_PURPLE = (120, 24, 74) -PAPAYA_WHIP = (255, 239, 213) -PARIS_GREEN = (80, 200, 120) -PASTEL_BLUE = (174, 198, 207) -PASTEL_BROWN = (131, 105, 83) -PASTEL_GRAY = (207, 207, 196) -PASTEL_GREEN = (119, 221, 119) -PASTEL_MAGENTA = (244, 154, 194) -PASTEL_ORANGE = (255, 179, 71) -PASTEL_PINK = (222, 165, 164) -PASTEL_PURPLE = (179, 158, 181) -PASTEL_RED = (255, 105, 97) -PASTEL_VIOLET = (203, 153, 201) -PASTEL_YELLOW = (253, 253, 150) -PATRIARCH = (128, 0, 128) -PAYNE_S_GREY = (83, 104, 120) -PEACH = (255, 229, 180) -PEACH_CRAYOLA = (255, 203, 164) -PEACH_ORANGE = (255, 204, 153) -PEACH_PUFF = (255, 218, 185) -PEACH_YELLOW = (250, 223, 173) -PEAR = (209, 226, 49) -PEARL = (234, 224, 200) -PEARL_AQUA = (136, 216, 192) -PEARLY_PURPLE = (183, 104, 162) -PERIDOT = (230, 226, 0) -PERIWINKLE = (204, 204, 255) -PERSIAN_BLUE = (28, 57, 187) -PERSIAN_GREEN = (0, 166, 147) -PERSIAN_INDIGO = (50, 18, 122) -PERSIAN_ORANGE = (217, 144, 88) -PERSIAN_PINK = (247, 127, 190) -PERSIAN_PLUM = (112, 28, 28) -PERSIAN_RED = (204, 51, 51) -PERSIAN_ROSE = (254, 40, 162) -PERSIMMON = (236, 88, 0) -PERU = (205, 133, 63) -PHLOX = (223, 0, 255) -PHTHALO_BLUE = (0, 15, 137) -PHTHALO_GREEN = (18, 53, 36) -PIGGY_PINK = (253, 221, 230) -PINE_GREEN = (1, 121, 111) -PINK = (255, 192, 203) -PINK_LACE = (255, 221, 244) -PINK_ORANGE = (255, 153, 102) -PINK_PEARL = (231, 172, 207) -PINK_SHERBET = (247, 143, 167) -PISTACHIO = (147, 197, 114) -PLATINUM = (229, 228, 226) -PLUM_TRADITIONAL = (142, 69, 133) -PLUM_WEB = (221, 160, 221) -PORTLAND_ORANGE = (255, 90, 54) -POWDER_BLUE_WEB = (176, 224, 230) -PRINCETON_ORANGE = (255, 143, 0) -PRUNE = (112, 28, 28) -PRUSSIAN_BLUE = (0, 49, 83) -PSYCHEDELIC_PURPLE = (223, 0, 255) -PUCE = (204, 136, 153) -PUMPKIN = (255, 117, 24) -PURPLE_HEART = (105, 53, 156) -PURPLE_HTML_CSS = (128, 0, 128) -PURPLE_MOUNTAIN_MAJESTY = (150, 120, 182) -PURPLE_MUNSELL = (159, 0, 197) -PURPLE_PIZZAZZ = (254, 78, 218) -PURPLE_TAUPE = (80, 64, 77) -PURPLE_X11 = (160, 32, 240) -QUARTZ = (81, 72, 79) -RACKLEY = (93, 138, 168) -RADICAL_RED = (255, 53, 94) -RAJAH = (251, 171, 96) -RASPBERRY = (227, 11, 93) -RASPBERRY_GLACE = (145, 95, 109) -RASPBERRY_PINK = (226, 80, 152) -RASPBERRY_ROSE = (179, 68, 108) -RAW_UMBER = (130, 102, 68) -RAZZLE_DAZZLE_ROSE = (255, 51, 204) -RAZZMATAZZ = (227, 37, 107) -RED = (255, 0, 0) -RED_BROWN = (165, 42, 42) -RED_DEVIL = (134, 1, 17) -RED_MUNSELL = (242, 0, 60) -RED_NCS = (196, 2, 51) -RED_ORANGE = (255, 83, 73) -RED_PIGMENT = (237, 28, 36) -RED_RYB = (254, 39, 18) -RED_VIOLET = (199, 21, 133) -REDWOOD = (171, 78, 82) -REGALIA = (82, 45, 128) -RESOLUTION_BLUE = (0, 35, 135) -RICH_BLACK = (0, 64, 64) -RICH_BRILLIANT_LAVENDER = (241, 167, 254) -RICH_CARMINE = (215, 0, 64) -RICH_ELECTRIC_BLUE = (8, 146, 208) -RICH_LAVENDER = (167, 107, 207) -RICH_LILAC = (182, 102, 210) -RICH_MAROON = (176, 48, 96) -RIFLE_GREEN = (65, 72, 51) -ROBIN_EGG_BLUE = (0, 204, 204) -ROSE = (255, 0, 127) -ROSE_BONBON = (249, 66, 158) -ROSE_EBONY = (103, 72, 70) -ROSE_GOLD = (183, 110, 121) -ROSE_MADDER = (227, 38, 54) -ROSE_PINK = (255, 102, 204) -ROSE_QUARTZ = (170, 152, 169) -ROSE_TAUPE = (144, 93, 93) -ROSE_VALE = (171, 78, 82) -ROSEWOOD = (101, 0, 11) -ROSSO_CORSA = (212, 0, 0) -ROSY_BROWN = (188, 143, 143) -ROYAL_AZURE = (0, 56, 168) -ROYAL_BLUE_TRADITIONAL = (0, 35, 102) -ROYAL_BLUE_WEB = (65, 105, 225) -ROYAL_FUCHSIA = (202, 44, 146) -ROYAL_PURPLE = (120, 81, 169) -ROYAL_YELLOW = (250, 218, 94) -RUBINE_RED = (209, 0, 86) -RUBY = (224, 17, 95) -RUBY_RED = (155, 17, 30) -RUDDY = (255, 0, 40) -RUDDY_BROWN = (187, 101, 40) -RUDDY_PINK = (225, 142, 150) -RUFOUS = (168, 28, 7) -RUSSET = (128, 70, 27) -RUST = (183, 65, 14) -RUSTY_RED = (218, 44, 67) -SACRAMENTO_STATE_GREEN = (0, 86, 63) -SADDLE_BROWN = (139, 69, 19) -SAFETY_ORANGE_BLAZE_ORANGE = (255, 103, 0) -SAFFRON = (244, 196, 48) -SALMON = (255, 140, 105) -SALMON_PINK = (255, 145, 164) -SAND = (194, 178, 128) -SAND_DUNE = (150, 113, 23) -SANDSTORM = (236, 213, 64) -SANDY_BROWN = (244, 164, 96) -SANDY_TAUPE = (150, 113, 23) -SANGRIA = (146, 0, 10) -SAP_GREEN = (80, 125, 42) -SAPPHIRE = (15, 82, 186) -SAPPHIRE_BLUE = (0, 103, 165) -SATIN_SHEEN_GOLD = (203, 161, 53) -SCARLET = (255, 36, 0) -SCARLET_CRAYOLA = (253, 14, 53) -SCHOOL_BUS_YELLOW = (255, 216, 0) -SCREAMIN_GREEN = (118, 255, 122) -SEA_BLUE = (0, 105, 148) -SEA_GREEN = (46, 139, 87) -SEAL_BROWN = (50, 20, 20) -SEASHELL = (255, 245, 238) -SELECTIVE_YELLOW = (255, 186, 0) -SEPIA = (112, 66, 20) -SHADOW = (138, 121, 93) -SHAMROCK_GREEN = (0, 158, 96) -SHOCKING_PINK = (252, 15, 192) -SHOCKING_PINK_CRAYOLA = (255, 111, 255) -SIENNA = (136, 45, 23) -SILVER = (192, 192, 192) -SINOPIA = (203, 65, 11) -SKOBELOFF = (0, 116, 116) -SKY_BLUE = (135, 206, 235) -SKY_MAGENTA = (207, 113, 175) -SLATE_BLUE = (106, 90, 205) -SLATE_GRAY = (112, 128, 144) -SMALT_DARK_POWDER_BLUE = (0, 51, 153) -SMOKEY_TOPAZ = (147, 61, 65) -SMOKY_BLACK = (16, 12, 8) -SNOW = (255, 250, 250) -SPIRO_DISCO_BALL = (15, 192, 252) -SPRING_BUD = (167, 252, 0) -SPRING_GREEN = (0, 255, 127) -ST_PATRICK_S_BLUE = (35, 41, 122) -STEEL_BLUE = (70, 130, 180) -STIL_DE_GRAIN_YELLOW = (250, 218, 94) -STIZZA = (153, 0, 0) -STORMCLOUD = (79, 102, 106) -STRAW = (228, 217, 111) -SUNGLOW = (255, 204, 51) -SUNSET = (250, 214, 165) -TAN = (210, 180, 140) -TANGELO = (249, 77, 0) -TANGERINE = (242, 133, 0) -TANGERINE_YELLOW = (255, 204, 0) -TANGO_PINK = (228, 113, 122) -TAUPE = (72, 60, 50) -TAUPE_GRAY = (139, 133, 137) -TEA_GREEN = (208, 240, 192) -TEA_ROSE_ORANGE = (248, 131, 121) -TEA_ROSE_ROSE = (244, 194, 194) -TEAL = (0, 128, 128) -TEAL_BLUE = (54, 117, 136) -TEAL_GREEN = (0, 130, 127) -TELEMAGENTA = (207, 52, 118) -TENN_TAWNY = (205, 87, 0) -TERRA_COTTA = (226, 114, 91) -THISTLE = (216, 191, 216) -THULIAN_PINK = (222, 111, 161) -TICKLE_ME_PINK = (252, 137, 172) -TIFFANY_BLUE = (10, 186, 181) -TIGER_S_EYE = (224, 141, 60) -TIMBERWOLF = (219, 215, 210) -TITANIUM_YELLOW = (238, 230, 0) -TOMATO = (255, 99, 71) -TOOLBOX = (116, 108, 192) -TOPAZ = (255, 200, 124) -TRACTOR_RED = (253, 14, 53) -TROLLEY_GREY = (128, 128, 128) -TROPICAL_RAIN_FOREST = (0, 117, 94) -TRUE_BLUE = (0, 115, 207) -TUFTS_BLUE = (65, 125, 193) -TUMBLEWEED = (222, 170, 136) -TURKISH_ROSE = (181, 114, 129) -TURQUOISE = (48, 213, 200) -TURQUOISE_BLUE = (0, 255, 239) -TURQUOISE_GREEN = (160, 214, 180) -TUSCAN_RED = (124, 72, 72) -TWILIGHT_LAVENDER = (138, 73, 107) -TYRIAN_PURPLE = (102, 2, 60) -UA_BLUE = (0, 51, 170) -UA_RED = (217, 0, 76) -UBE = (136, 120, 195) -UCLA_BLUE = (83, 104, 149) -UCLA_GOLD = (255, 179, 0) -UFO_GREEN = (60, 208, 112) -ULTRA_PINK = (255, 111, 255) -ULTRAMARINE = (18, 10, 143) -ULTRAMARINE_BLUE = (65, 102, 245) -UMBER = (99, 81, 71) -UNBLEACHED_SILK = (255, 221, 202) -UNITED_NATIONS_BLUE = (91, 146, 229) -UNIVERSITY_OF_CALIFORNIA_GOLD = (183, 135, 39) -UNMELLOW_YELLOW = (255, 255, 102) -UP_FOREST_GREEN = (1, 68, 33) -UP_MAROON = (123, 17, 19) -UPSDELL_RED = (174, 32, 41) -UROBILIN = (225, 173, 33) -USAFA_BLUE = (0, 79, 152) -USC_CARDINAL = (153, 0, 0) -USC_GOLD = (255, 204, 0) -UTAH_CRIMSON = (211, 0, 63) -VANILLA = (243, 229, 171) -VEGAS_GOLD = (197, 179, 88) -VENETIAN_RED = (200, 8, 21) -VERDIGRIS = (67, 179, 174) -VERMILION_CINNABAR = (227, 66, 52) -VERMILION_PLOCHERE = (217, 96, 59) -VERONICA = (160, 32, 240) -VIOLET = (143, 0, 255) -VIOLET_BLUE = (50, 74, 178) -VIOLET_COLOR_WHEEL = (127, 0, 255) -VIOLET_RYB = (134, 1, 175) -VIOLET_WEB = (238, 130, 238) -VIRIDIAN = (64, 130, 109) -VIVID_AUBURN = (146, 39, 36) -VIVID_BURGUNDY = (159, 29, 53) -VIVID_CERISE = (218, 29, 129) -VIVID_TANGERINE = (255, 160, 137) -VIVID_VIOLET = (159, 0, 255) -WARM_BLACK = (0, 66, 66) -WATERSPOUT = (164, 244, 249) -WENGE = (100, 84, 82) -WHEAT = (245, 222, 179) -WHITE = (255, 255, 255) -WHITE_SMOKE = (245, 245, 245) -WILD_BLUE_YONDER = (162, 173, 208) -WILD_STRAWBERRY = (255, 67, 164) -WILD_WATERMELON = (252, 108, 133) -WINE = (114, 47, 55) -WINE_DREGS = (103, 49, 71) -WISTERIA = (201, 160, 220) -WOOD_BROWN = (193, 154, 107) -XANADU = (115, 134, 120) -YALE_BLUE = (15, 77, 146) -YELLOW = (255, 255, 0) -YELLOW_GREEN = (154, 205, 50) -YELLOW_MUNSELL = (239, 204, 0) -YELLOW_NCS = (255, 211, 0) -YELLOW_ORANGE = (255, 174, 66) -YELLOW_PROCESS = (255, 239, 0) -YELLOW_RYB = (254, 254, 51) -ZAFFRE = (0, 20, 168) -ZINNWALDITE_BROWN = (44, 22, 8) diff --git a/skimage/novice/novice.py b/skimage/novice/novice.py index 37eda63c..bc39e4a1 100644 --- a/skimage/novice/novice.py +++ b/skimage/novice/novice.py @@ -1,11 +1,21 @@ import os import imghdr +from collections import namedtuple import numpy as np from skimage import io from skimage import img_as_ubyte from skimage.transform import resize +from skimage.color import color_dict + + +# Convert colors from `skimage.color` to uint8 and allow access through +# dict or a named tuple. +color_dict = dict((name, tuple(int(255 * c + 0.5) for c in rgb)) + for name, rgb in color_dict.iteritems()) +colors = namedtuple('colors', color_dict.keys())(**color_dict) + def open(path): """Return Picture object from the given image path.""" From 087d422ebc4074f166b8e9ca72701e921fbf631d Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 5 Jul 2013 22:24:49 -0500 Subject: [PATCH 15/51] Rename novice package as per convention --- skimage/novice/__init__.py | 4 +++- skimage/novice/{novice.py => _novice.py} | 0 2 files changed, 3 insertions(+), 1 deletion(-) rename skimage/novice/{novice.py => _novice.py} (100%) diff --git a/skimage/novice/__init__.py b/skimage/novice/__init__.py index fad92768..c315ffc5 100644 --- a/skimage/novice/__init__.py +++ b/skimage/novice/__init__.py @@ -69,5 +69,7 @@ jpeg False """ +from ._novice import Picture, open, colors, color_dict -from .novice import Picture, open, colors, color_dict + +__all__ = ['Picture', 'open', 'colors', 'color_dict'] diff --git a/skimage/novice/novice.py b/skimage/novice/_novice.py similarity index 100% rename from skimage/novice/novice.py rename to skimage/novice/_novice.py From f47c5a7be7ee9b9b3972999266dff530a7bdce52 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 5 Jul 2013 23:04:54 -0500 Subject: [PATCH 16/51] Switch argument order for clarity --- skimage/novice/_novice.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index bc39e4a1..dafad67d 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -253,12 +253,12 @@ class Picture(object): ---------- path : str Path to an image file to load. + image : array + Raw RGB image data [0-255] size : tuple Size of the empty image to create (width, height). color : tuple Color to fill empty image if size is given (red, green, blue) [0-255]. - image : array_like - Raw RGB image data [0-255] Notes ----- @@ -296,7 +296,7 @@ class Picture(object): >>> pic[:, pic.height-1] = (255, 0, 0) """ - def __init__(self, path=None, size=None, color=None, image=None): + def __init__(self, path=None, image=None, size=None, color=None): # Can only provide either path or size, but not both. if (path and size) or (path and image) or (size and image): assert False, "Can only provide path, size, or image." From 9385e735866f71892c566c0c788f307557820cb1 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 5 Jul 2013 23:05:13 -0500 Subject: [PATCH 17/51] Clean up testing --- skimage/novice/tests/test_novice.py | 76 +++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 19a2d34c..73aba8e8 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -2,7 +2,7 @@ import os import tempfile import numpy as np -from numpy.testing import assert_equal, assert_raises +from numpy.testing import assert_equal, assert_raises, raises from skimage import novice from skimage import data_dir @@ -18,7 +18,7 @@ def test_pic_info(): assert_equal(pic.size, (665, 500)) assert_equal(pic.width, 665) assert_equal(pic.height, 500) - assert_equal(pic.modified, False) + assert not pic.modified assert_equal(pic.scale, 1) @@ -40,23 +40,65 @@ def test_modify(): for p in pic: if p.x < (pic.width / 2): - assert_equal(p.red <= 128, True) - assert_equal(p.green <= 128, True) - assert_equal(p.blue <= 128, True) + assert p.red <= 128 + assert p.green <= 128 + assert p.blue <= 128 s = pic.size pic.size = (pic.width / 2, pic.height / 2) assert_equal(pic.size, (int(s[0] / 2), int(s[1] / 2))) - assert_equal(pic.modified, True) - assert_equal(pic.path, None) + assert pic.modified + assert pic.path is None + + +def test_pixel_rgb(): + pic = novice.Picture(size=(3, 3), color=(10, 10, 10)) + pixel = pic[0, 0] + pixel.rgb = range(3) + + assert_equal(pixel.rgb, range(3)) + for i, channel in enumerate((pixel.red, pixel.green, pixel.blue)): + assert_equal(channel, i) + + pixel.red = 3 + pixel.green = 4 + pixel.blue = 5 + assert_equal(pixel.rgb, np.arange(3) + 3) + + for i, channel in enumerate((pixel.red, pixel.green, pixel.blue)): + assert_equal(channel, i + 3) + + +@raises(ValueError) +def test_pixel_rgb_raises(): + pixel = novice.Picture(size=(1, 1))[0, 0] + pixel.rgb = (-1, -1, -1) + + +@raises(ValueError) +def test_pixel_red_raises(): + pixel = novice.Picture(size=(1, 1))[0, 0] + pixel.red = 256 + + +@raises(ValueError) +def test_pixel_green_raises(): + pixel = novice.Picture(size=(1, 1))[0, 0] + pixel.green = 256 + + +@raises(ValueError) +def test_pixel_blue_raises(): + pixel = novice.Picture(size=(1, 1))[0, 0] + pixel.blue = 256 def test_modified_on_set(): pic = novice.Picture(SMALL_IMAGE_PATH) pic[0, 0] = (1, 1, 1) - assert_equal(pic.modified, True) - assert_equal(pic.path, None) + assert pic.modified + assert pic.path is None def test_modified_on_set_pixel(): @@ -65,27 +107,27 @@ def test_modified_on_set_pixel(): pixel = pic[0, 0] pixel.green = 1 - assert_equal(pic.modified, True) + assert pic.modified def test_update_on_save(): pic = novice.Picture(image=np.zeros((3, 3))) pic.size = (6, 6) - assert_equal(pic.modified, True) - assert_equal(pic.path, None) + assert pic.modified + assert pic.path is None with tempfile.NamedTemporaryFile(suffix=".jpg") as tmp: pic.save(tmp.name) - assert_equal(pic.modified, False) + assert not pic.modified assert_equal(pic.path, os.path.abspath(tmp.name)) assert_equal(pic.format, "jpeg") def test_indexing(): - pic = novice.open(SMALL_IMAGE_PATH) + image = 128 * np.ones((10, 10, 3), dtype=np.uint8) + pic = novice.Picture(image=image) - # Slicing pic[0:5, 0:5] = (0, 0, 0) for p in pic: if (p.x < 5) and (p.y < 5): @@ -118,6 +160,10 @@ def test_indexing(): assert_equal(p.green, 0) assert_equal(p.blue, 255) + +def test_indexing_bounds(): + pic = novice.open(SMALL_IMAGE_PATH) + # Outside bounds assert_raises(IndexError, lambda: pic[pic.width, pic.height]) From c5bfed26cd797d86fe1fd765e6b55055dbebf8fb Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 5 Jul 2013 23:10:39 -0500 Subject: [PATCH 18/51] Fix validation bug and add test --- skimage/novice/_novice.py | 7 +------ skimage/novice/tests/test_novice.py | 6 ++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index dafad67d..a1a0e6f4 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -95,12 +95,7 @@ class Pixel(object): @rgb.setter def rgb(self, value): - for v in value: - self._validate(v) - - self._red = value[0] - self._green = value[1] - self._blue = value[2] + self._red, self._green, self._blue = (self._validate(v) for v in value) self._setpixel() def _validate(self, value): diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 73aba8e8..ddbe3f1c 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -70,6 +70,12 @@ def test_pixel_rgb(): assert_equal(channel, i + 3) +def test_pixel_rgb_float(): + pixel = novice.Picture(size=(1, 1))[0, 0] + pixel.rgb = (1.1, 1.1, 1.1) + assert_equal(pixel.rgb, (1, 1, 1)) + + @raises(ValueError) def test_pixel_rgb_raises(): pixel = novice.Picture(size=(1, 1))[0, 0] From 3619e6f2f294289fe65186151415e2b4b8737e42 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sun, 7 Jul 2013 22:20:39 -0500 Subject: [PATCH 19/51] Rename image to array --- skimage/novice/_novice.py | 86 ++++++++++++++--------------- skimage/novice/tests/test_novice.py | 8 +-- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index a1a0e6f4..78f3a4f3 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -29,7 +29,7 @@ class Pixel(object): ---------- pic : Picture The Picture object that this pixel references. - image : array_like + array : array_like Byte array with raw image data (RGB). x : int Horizontal coordinate of this pixel (left = 0). @@ -39,9 +39,9 @@ class Pixel(object): RGB tuple with red, green, and blue components (0-255) """ - def __init__(self, pic, image, x, y, rgb): + def __init__(self, pic, array, x, y, rgb): self._picture = pic - self._image = image + self._array = array self._x = x self._y = y self._red = self._validate(rgb[0]) @@ -117,8 +117,8 @@ class Pixel(object): """ row = self._picture.height - self._y - 1 - self._picture._image[row, self._x] = self.rgb - self._picture._image_modified() + self._picture._array[row, self._x] = self.rgb + self._picture._array_modified() def __repr__(self): args = self.red, self.green, self.blue @@ -169,11 +169,11 @@ class PixelGroup(object): # array dimensions are row, column (i.e. y, x) self._key = (key[1], key[0]) - self._image = pic._image + self._array = pic._array # Save slice for _getdim operations. - # This allows you to swap parts of an image. - self._slice = self._image[self._key[0], self._key[1]] + # This allows you to swap parts of an array. + self._slice = self._array[self._key[0], self._key[1]] shape = self._getdim(0).shape self.size = (shape[1], shape[0]) @@ -188,7 +188,7 @@ class PixelGroup(object): """ Sets a specific dimension in the raw image data slice. """ - self._image[self._key[0], self._key[1], dim] = value + self._array[self._key[0], self._key[1], dim] = value @property def red(self): @@ -248,16 +248,16 @@ class Picture(object): ---------- path : str Path to an image file to load. - image : array + array : array Raw RGB image data [0-255] size : tuple - Size of the empty image to create (width, height). + Size of the empty array to create (width, height). color : tuple - Color to fill empty image if size is given (red, green, blue) [0-255]. + Color to fill empty array if size is given (red, green, blue) [0-255]. Notes ----- - Cannot provide more than one of 'path' and 'size' and 'image'. + Cannot provide more than one of 'path' and 'size' and 'array'. Can only provide 'color' if 'size' provided. Examples @@ -274,7 +274,7 @@ class Picture(object): >>> import numpy as np >>> data = np.zeros(shape=(200, 100, 3), dtype=np.uint8) >>> data[:, :, 0] = 255 # Set red component to maximum - >>> pic = Picture(image=data) + >>> pic = Picture(array=data) Get the bottom-left pixel >>> pic[0, 0] @@ -291,37 +291,37 @@ class Picture(object): >>> pic[:, pic.height-1] = (255, 0, 0) """ - def __init__(self, path=None, image=None, size=None, color=None): + def __init__(self, path=None, array=None, size=None, color=None): # Can only provide either path or size, but not both. - if (path and size) or (path and image) or (size and image): - assert False, "Can only provide path, size, or image." + if (path and size) or (path and array) or (size and array): + assert False, "Can only provide path, size, or array." # Opening a particular file. Convert the image to RGB # automatically so (r, g, b) tuples can be used # everywhere. elif path is not None: - self._image = img_as_ubyte(io.imread(path)) + self._array = img_as_ubyte(io.imread(path)) self._path = path self._format = imghdr.what(path) - # Creating a particular size of image. + # Creating a particular size of array. elif size is not None: if color is None: color = (0, 0, 0) # skimage dimensions are flipped: y, x - self._image = np.zeros((size[1], size[0], 3), "uint8") - self._image[:, :] = color + self._array = np.zeros((size[1], size[0], 3), "uint8") + self._array[:, :] = color self._path = None self._format = None - elif image is not None: - self._image = image + elif array is not None: + self._array = array self._path = None self._format = None - # Must have provided 'path', 'size', or 'image'. + # Must have provided 'path', 'size', or 'array'. else: - assert False, "Must provide one of path, size, or image." + assert False, "Must provide one of path, size, or array." # Common setup. self._modified = False @@ -365,7 +365,7 @@ class Picture(object): return Picture(color=color, size=size) @staticmethod - def from_image(image): + def from_array(array): """Creates a single color Picture. Parameters @@ -382,7 +382,7 @@ class Picture(object): A Picture with the given color and size. """ - return Picture(image=image) + return Picture(array=array) def save(self, path): """Saves the picture to the given path. @@ -393,7 +393,7 @@ class Picture(object): Path to save the picture (with file extension). """ - io.imsave(path, self._rescale(self._image)) + io.imsave(path, self._rescale(self._array)) self._modified = False self._path = os.path.abspath(path) self._format = imghdr.what(path) @@ -408,7 +408,7 @@ class Picture(object): """True if the picture has changed.""" return self._modified - def _image_modified(self): + def _array_modified(self): self._modified = True self._path = None @@ -421,7 +421,7 @@ class Picture(object): def size(self): """The size (width, height) of the picture.""" # array dimensions are flipped: y, x - return (self._image.shape[1], self._image.shape[0]) + return (self._array.shape[1], self._array.shape[0]) @size.setter def size(self, value): @@ -429,10 +429,10 @@ class Picture(object): # Don't resize if no change in size if (value[0] != self.width) or (value[1] != self.height): # skimage dimensions are flipped: y, x - self._image = img_as_ubyte(resize(self._image, + self._array = img_as_ubyte(resize(self._array, (int(value[1]), int(value[0])), order=0)) - self._image_modified() + self._array_modified() except TypeError: msg = "Expected (width, height), but got {0} instead!" raise TypeError(msg.format(value)) @@ -456,16 +456,16 @@ class Picture(object): self.size = (self.width, value) def _repr_html_(self): - return io.Image(self._rescale(self._image)) + return io.Image(self._rescale(self._array)) def _repr_png_(self): - return io.Image(self._rescale(self._image)) + return io.Image(self._rescale(self._array)) def show(self): """Displays the image in a separate window. """ - io.imshow(self._rescale(self._image)) + io.imshow(self._rescale(self._array)) def _makepixel(self, xy): """ Creates a Pixel object for a given x, y location. @@ -477,22 +477,22 @@ class Picture(object): """ # skimage dimensions are flipped: y, x - rgb = self._image[self.height - xy[1] - 1, xy[0]] - return Pixel(self, self._image, xy[0], xy[1], rgb) + rgb = self._array[self.height - xy[1] - 1, xy[0]] + return Pixel(self, self._array, xy[0], xy[1], rgb) - def _rescale(self, image): + def _rescale(self, array): """Inflates image according to scale factor. Parameters ---------- - image : array + array : array Raw RGB image data to rescale using nearest neighbor algorithm. """ if self.scale == 1: - return image + return array new_size = (self.height * self.scale, self.width * self.scale) - return img_as_ubyte(resize(image, new_size, order=0)) + return img_as_ubyte(resize(array, new_size, order=0)) def __iter__(self): """Iterates over all pixels in the image.""" @@ -518,12 +518,12 @@ class Picture(object): self[key[0], key[1]].rgb = value elif isinstance(value, PixelGroup): src_key = self[key[0], key[1]]._key - self._image[src_key] = value._image[value._key] + self._array[src_key] = value._array[value._key] else: raise TypeError("Invalid value type") else: raise TypeError("Invalid key type") - self._image_modified() + self._array_modified() def __repr__(self): args = self.format, self.path, self.modified diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index ddbe3f1c..395dc5e0 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -109,7 +109,7 @@ def test_modified_on_set(): def test_modified_on_set_pixel(): data = np.zeros(shape=(10, 5, 3), dtype=np.uint8) - pic = novice.Picture(image=data) + pic = novice.Picture(array=data) pixel = pic[0, 0] pixel.green = 1 @@ -117,7 +117,7 @@ def test_modified_on_set_pixel(): def test_update_on_save(): - pic = novice.Picture(image=np.zeros((3, 3))) + pic = novice.Picture(array=np.zeros((3, 3))) pic.size = (6, 6) assert pic.modified assert pic.path is None @@ -131,8 +131,8 @@ def test_update_on_save(): def test_indexing(): - image = 128 * np.ones((10, 10, 3), dtype=np.uint8) - pic = novice.Picture(image=image) + array = 128 * np.ones((10, 10, 3), dtype=np.uint8) + pic = novice.Picture(array=array) pic[0:5, 0:5] = (0, 0, 0) for p in pic: From 8869724b51de7fb241159dc8546d4c4b4d16c6ae Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sun, 7 Jul 2013 22:41:04 -0500 Subject: [PATCH 20/51] Remove color and size from Picture.__init__ Also rename `from_color` to `from_size`. --- skimage/novice/_novice.py | 50 +++++++++-------------------- skimage/novice/tests/test_novice.py | 12 +++---- 2 files changed, 21 insertions(+), 41 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 78f3a4f3..6ab629ad 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -6,8 +6,8 @@ import numpy as np from skimage import io from skimage import img_as_ubyte from skimage.transform import resize - from skimage.color import color_dict +from skimage._shared import six # Convert colors from `skimage.color` to uint8 and allow access through @@ -291,37 +291,19 @@ class Picture(object): >>> pic[:, pic.height-1] = (255, 0, 0) """ - def __init__(self, path=None, array=None, size=None, color=None): - # Can only provide either path or size, but not both. - if (path and size) or (path and array) or (size and array): - assert False, "Can only provide path, size, or array." - - # Opening a particular file. Convert the image to RGB - # automatically so (r, g, b) tuples can be used - # everywhere. + def __init__(self, path=None, array=None): + if path is not None and array is not None: + ValueError("Only provide path or array not both.") elif path is not None: self._array = img_as_ubyte(io.imread(path)) self._path = path self._format = imghdr.what(path) - - # Creating a particular size of array. - elif size is not None: - if color is None: - color = (0, 0, 0) - - # skimage dimensions are flipped: y, x - self._array = np.zeros((size[1], size[0], 3), "uint8") - self._array[:, :] = color - self._path = None - self._format = None elif array is not None: self._array = array self._path = None self._format = None - - # Must have provided 'path', 'size', or 'array'. else: - assert False, "Must provide one of path, size, or array." + ValueError("Must provide path or array.") # Common setup. self._modified = False @@ -345,24 +327,22 @@ class Picture(object): return Picture(path=path) @staticmethod - def from_color(color, size): - """Creates a single color Picture. + def from_size(size, color='black'): + """Return a Picture of the specified size and a uniform color. Parameters ---------- - color : tuple - RGB tuple with the fill color for the picture [0-255] - size : tuple Width and height of the picture in pixels. - - Returns - ------- - pic : Picture - A Picture with the given color and size. - + color : tuple or str + RGB tuple with the fill color for the picture [0-255] or a valid + key in `color_dict`. """ - return Picture(color=color, size=size) + if isinstance(color, six.string_types): + color = color_dict[color] + rgb_size = tuple(size) + (3,) + array = np.ones(rgb_size, dtype=np.uint8) * color + return Picture(array=array) @staticmethod def from_array(array): diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 395dc5e0..9e2e28e4 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -53,7 +53,7 @@ def test_modify(): def test_pixel_rgb(): - pic = novice.Picture(size=(3, 3), color=(10, 10, 10)) + pic = novice.Picture.from_size((3, 3), color=(10, 10, 10)) pixel = pic[0, 0] pixel.rgb = range(3) @@ -71,32 +71,32 @@ def test_pixel_rgb(): def test_pixel_rgb_float(): - pixel = novice.Picture(size=(1, 1))[0, 0] + pixel = novice.Picture.from_size((1, 1))[0, 0] pixel.rgb = (1.1, 1.1, 1.1) assert_equal(pixel.rgb, (1, 1, 1)) @raises(ValueError) def test_pixel_rgb_raises(): - pixel = novice.Picture(size=(1, 1))[0, 0] + pixel = novice.Picture.from_size((1, 1))[0, 0] pixel.rgb = (-1, -1, -1) @raises(ValueError) def test_pixel_red_raises(): - pixel = novice.Picture(size=(1, 1))[0, 0] + pixel = novice.Picture.from_size((1, 1))[0, 0] pixel.red = 256 @raises(ValueError) def test_pixel_green_raises(): - pixel = novice.Picture(size=(1, 1))[0, 0] + pixel = novice.Picture.from_size((1, 1))[0, 0] pixel.green = 256 @raises(ValueError) def test_pixel_blue_raises(): - pixel = novice.Picture(size=(1, 1))[0, 0] + pixel = novice.Picture.from_size((1, 1))[0, 0] pixel.blue = 256 From a9512327021e35f5419a3287e2afd141ebe0e6da Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sun, 7 Jul 2013 22:44:41 -0500 Subject: [PATCH 21/51] Remove `from_path` and `from_array` methods Having these methods and the constructor arguments is a bit redundant. --- skimage/novice/_novice.py | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 6ab629ad..6a1dc066 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -309,23 +309,6 @@ class Picture(object): self._modified = False self.scale = 1 - @staticmethod - def from_path(path): - """Creates a Picture from an image file. - - Parameters - ---------- - path : str - Path to the image file. - - Returns - ------- - pic : Picture - A Picture with the image file data loaded. - - """ - return Picture(path=path) - @staticmethod def from_size(size, color='black'): """Return a Picture of the specified size and a uniform color. @@ -344,26 +327,6 @@ class Picture(object): array = np.ones(rgb_size, dtype=np.uint8) * color return Picture(array=array) - @staticmethod - def from_array(array): - """Creates a single color Picture. - - Parameters - ---------- - color : tuple - RGB tuple with the fill color for the picture [0-255] - - size : tuple - Width and height of the picture in pixels. - - Returns - ------- - pic : Picture - A Picture with the given color and size. - - """ - return Picture(array=array) - def save(self, path): """Saves the picture to the given path. From 7c1de579281bce6ca609a71ffe19f9390de7174f Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 27 Sep 2013 19:12:52 -0500 Subject: [PATCH 22/51] Simplify data access and add tests --- skimage/novice/_novice.py | 101 +++++++++++++++------------- skimage/novice/tests/test_novice.py | 16 ++++- 2 files changed, 70 insertions(+), 47 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 6a1dc066..a25c018a 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -22,6 +22,12 @@ def open(path): return Picture(path=os.path.abspath(path)) +def _verify_picture_index(index): + """Raise error if picture index is not a 2D index/slice.""" + if not (isinstance(index, tuple) and len(index) == 2): + raise IndexError("Expected 2D index but got {!r}".format(index)) + + class Pixel(object): """A single pixel in a Picture. @@ -41,7 +47,6 @@ class Pixel(object): """ def __init__(self, pic, array, x, y, rgb): self._picture = pic - self._array = array self._x = x self._y = y self._red = self._validate(rgb[0]) @@ -116,8 +121,7 @@ class Pixel(object): NOTE: Using Cartesian coordinate system! """ - row = self._picture.height - self._y - 1 - self._picture._array[row, self._x] = self.rgb + self._picture._xy_array[self._x, self._y] = self.rgb self._picture._array_modified() def __repr__(self): @@ -169,11 +173,8 @@ class PixelGroup(object): # array dimensions are row, column (i.e. y, x) self._key = (key[1], key[0]) - self._array = pic._array - # Save slice for _getdim operations. - # This allows you to swap parts of an array. - self._slice = self._array[self._key[0], self._key[1]] + self._array = pic._array[self._key] shape = self._getdim(0).shape self.size = (shape[1], shape[0]) @@ -182,13 +183,17 @@ class PixelGroup(object): """Gets a specific dimension out of the raw image data slice. """ - return self._slice[:, :, dim] + return self._array[:, :, dim] def _setdim(self, dim, value): """ Sets a specific dimension in the raw image data slice. """ - self._array[self._key[0], self._key[1], dim] = value + self._array[:, :, dim] = value + + @property + def array(self): + return self._array @property def red(self): @@ -235,7 +240,7 @@ class PixelGroup(object): for x in x_idx: for y in y_idx: - yield self._pic._makepixel((x, y)) + yield self._pic._makepixel(x, y) def __repr__(self): return "PixelGroup ({0} pixels)".format(self.size[0] * self.size[1]) @@ -295,11 +300,11 @@ class Picture(object): if path is not None and array is not None: ValueError("Only provide path or array not both.") elif path is not None: - self._array = img_as_ubyte(io.imread(path)) + self.array = img_as_ubyte(io.imread(path)) self._path = path self._format = imghdr.what(path) elif array is not None: - self._array = array + self.array = array self._path = None self._format = None else: @@ -327,6 +332,17 @@ class Picture(object): array = np.ones(rgb_size, dtype=np.uint8) * color return Picture(array=array) + @property + def array(self): + return self._array + + @array.setter + def array(self, array): + self._array = array + # Keep a view of the array with origin at lower-right corner. + # Transpose axis 0 and 1, and leave RGB channels unchanged. + self._xy_array = np.transpose(array[::-1], (1, 0, 2)) + def save(self, path): """Saves the picture to the given path. @@ -336,7 +352,7 @@ class Picture(object): Path to save the picture (with file extension). """ - io.imsave(path, self._rescale(self._array)) + io.imsave(path, self._rescale(self.array)) self._modified = False self._path = os.path.abspath(path) self._format = imghdr.what(path) @@ -363,8 +379,7 @@ class Picture(object): @property def size(self): """The size (width, height) of the picture.""" - # array dimensions are flipped: y, x - return (self._array.shape[1], self._array.shape[0]) + return self._xy_array.shape[:2] @size.setter def size(self, value): @@ -372,8 +387,9 @@ class Picture(object): # Don't resize if no change in size if (value[0] != self.width) or (value[1] != self.height): # skimage dimensions are flipped: y, x - self._array = img_as_ubyte(resize(self._array, - (int(value[1]), int(value[0])), order=0)) + new_size = (int(value[1]), int(value[0])) + new_array = resize(self.array, new_size, order=0) + self.array = img_as_ubyte(new_array) self._array_modified() except TypeError: @@ -399,29 +415,28 @@ class Picture(object): self.size = (self.width, value) def _repr_html_(self): - return io.Image(self._rescale(self._array)) + return io.Image(self._rescale(self.array)) def _repr_png_(self): - return io.Image(self._rescale(self._array)) + return io.Image(self._rescale(self.array)) def show(self): """Displays the image in a separate window. """ - io.imshow(self._rescale(self._array)) + io.imshow(self._rescale(self.array)) - def _makepixel(self, xy): + def _makepixel(self, x, y): """ Creates a Pixel object for a given x, y location. Parameters ---------- - xy : tuple - Cartesian coordinates to create a Pixel object for. + x, y : int + Cartesian coordinates of the Pixel object. """ - # skimage dimensions are flipped: y, x - rgb = self._array[self.height - xy[1] - 1, xy[0]] - return Pixel(self, self._array, xy[0], xy[1], rgb) + rgb = self._xy_array[x, y] + return Pixel(self, self.array, x, y, rgb) def _rescale(self, array): """Inflates image according to scale factor. @@ -441,31 +456,27 @@ class Picture(object): """Iterates over all pixels in the image.""" for x in xrange(self.width): for y in xrange(self.height): - yield self._makepixel((x, y)) + yield self._makepixel(x, y) def __getitem__(self, key): - if isinstance(key, tuple) and len(key) == 2: - if isinstance(key[0], int) and isinstance(key[1], int): - if key[0] < 0 or key[1] < 0: - raise IndexError("Negative indices not supported") - - return self._makepixel((key[0], key[1])) - else: - return PixelGroup(self, key) + """Return `PixelGroup`s for slices and `Pixel`s for indexes.""" + _verify_picture_index(key) + if all(isinstance(index, int) for index in key): + if any(index < 0 for index in key): + raise IndexError("Negative indices not supported") + return self._makepixel(*key) else: - raise TypeError("Invalid key type") + return PixelGroup(self, key) def __setitem__(self, key, value): - if isinstance(key, tuple) and len(key) == 2: - if isinstance(value, tuple): - self[key[0], key[1]].rgb = value - elif isinstance(value, PixelGroup): - src_key = self[key[0], key[1]]._key - self._array[src_key] = value._array[value._key] - else: - raise TypeError("Invalid value type") + _verify_picture_index(key) + if isinstance(value, tuple): + self[key].rgb = value + elif isinstance(value, PixelGroup): + src_key = self[key]._key + self.array[src_key] = value._array else: - raise TypeError("Invalid key type") + raise TypeError("Invalid value type") self._array_modified() def __repr__(self): diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 9e2e28e4..1e455767 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -2,7 +2,7 @@ import os import tempfile import numpy as np -from numpy.testing import assert_equal, assert_raises, raises +from numpy.testing import assert_equal, assert_raises, raises, assert_allclose from skimage import novice from skimage import data_dir @@ -117,7 +117,7 @@ def test_modified_on_set_pixel(): def test_update_on_save(): - pic = novice.Picture(array=np.zeros((3, 3))) + pic = novice.Picture(array=np.zeros((3, 3, 3))) pic.size = (6, 6) assert pic.modified assert pic.path is None @@ -167,6 +167,14 @@ def test_indexing(): assert_equal(p.blue, 255) +def test_pixel_group(): + array = np.tile(np.arange(0, 10)[np.newaxis, :, np.newaxis], (1, 1, 3)) + pic = novice.Picture(array=array) + index = (slice(None), slice(3, 8)) + pixel_group = pic[index[::-1]] + assert_allclose(pixel_group.array, array[index]) + + def test_indexing_bounds(): pic = novice.open(SMALL_IMAGE_PATH) @@ -180,6 +188,10 @@ def test_indexing_bounds(): # Step sizes > 1 not supported assert_raises(IndexError, lambda: pic[::2, ::2]) + # Only 2D indexes supported + assert_raises(IndexError, lambda: pic[1]) + assert_raises(IndexError, lambda: pic[1, 2, 3]) + def test_slicing(): cut = 40 From b8443bd1e2dd8736a2eb53795b3a3c1e9d432f73 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 27 Sep 2013 22:57:44 -0500 Subject: [PATCH 23/51] Remove unnecessary try-except. --- skimage/novice/_novice.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index a25c018a..9c24b11e 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -383,18 +383,14 @@ class Picture(object): @size.setter def size(self, value): - try: - # Don't resize if no change in size - if (value[0] != self.width) or (value[1] != self.height): - # skimage dimensions are flipped: y, x - new_size = (int(value[1]), int(value[0])) - new_array = resize(self.array, new_size, order=0) - self.array = img_as_ubyte(new_array) + # Don't resize if no change in size + if (value[0] != self.width) or (value[1] != self.height): + # skimage dimensions are flipped: y, x + new_size = (int(value[1]), int(value[0])) + new_array = resize(self.array, new_size, order=0) + self.array = img_as_ubyte(new_array) - self._array_modified() - except TypeError: - msg = "Expected (width, height), but got {0} instead!" - raise TypeError(msg.format(value)) + self._array_modified() @property def width(self): From 450d04d2b3a1e272875bfb8d86688d7a3768b9d8 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 27 Sep 2013 23:00:55 -0500 Subject: [PATCH 24/51] Simplify private docstrings --- skimage/novice/_novice.py | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 9c24b11e..3ba45d37 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -180,15 +180,11 @@ class PixelGroup(object): self.size = (shape[1], shape[0]) def _getdim(self, dim): - """Gets a specific dimension out of the raw image data slice. - - """ + """Return a specific dimension out of the raw image data slice.""" return self._array[:, :, dim] def _setdim(self, dim, value): - """ Sets a specific dimension in the raw image data slice. - - """ + """Set a specific dimension in the raw image data slice.""" self._array[:, :, dim] = value @property @@ -310,7 +306,6 @@ class Picture(object): else: ValueError("Must provide path or array.") - # Common setup. self._modified = False self.scale = 1 @@ -417,32 +412,16 @@ class Picture(object): return io.Image(self._rescale(self.array)) def show(self): - """Displays the image in a separate window. - - """ + """Display the image.""" io.imshow(self._rescale(self.array)) def _makepixel(self, x, y): - """ Creates a Pixel object for a given x, y location. - - Parameters - ---------- - x, y : int - Cartesian coordinates of the Pixel object. - - """ + """Create a Pixel object for a given x, y location.""" rgb = self._xy_array[x, y] return Pixel(self, self.array, x, y, rgb) def _rescale(self, array): - """Inflates image according to scale factor. - - Parameters - ---------- - array : array - Raw RGB image data to rescale using nearest neighbor algorithm. - - """ + """Rescale image according to scale factor.""" if self.scale == 1: return array new_size = (self.height * self.scale, self.width * self.scale) From 7999e3f95e96fc15df464d1758440b59d4c22d5b Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 27 Sep 2013 23:11:00 -0500 Subject: [PATCH 25/51] Refactor and add error tests --- skimage/novice/tests/test_novice.py | 116 +++++++++++++++++----------- 1 file changed, 73 insertions(+), 43 deletions(-) diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 1e455767..983b7e00 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -2,7 +2,7 @@ import os import tempfile import numpy as np -from numpy.testing import assert_equal, assert_raises, raises, assert_allclose +from numpy.testing import assert_equal, raises, assert_allclose from skimage import novice from skimage import data_dir @@ -76,30 +76,6 @@ def test_pixel_rgb_float(): assert_equal(pixel.rgb, (1, 1, 1)) -@raises(ValueError) -def test_pixel_rgb_raises(): - pixel = novice.Picture.from_size((1, 1))[0, 0] - pixel.rgb = (-1, -1, -1) - - -@raises(ValueError) -def test_pixel_red_raises(): - pixel = novice.Picture.from_size((1, 1))[0, 0] - pixel.red = 256 - - -@raises(ValueError) -def test_pixel_green_raises(): - pixel = novice.Picture.from_size((1, 1))[0, 0] - pixel.green = 256 - - -@raises(ValueError) -def test_pixel_blue_raises(): - pixel = novice.Picture.from_size((1, 1))[0, 0] - pixel.blue = 256 - - def test_modified_on_set(): pic = novice.Picture(SMALL_IMAGE_PATH) pic[0, 0] = (1, 1, 1) @@ -175,24 +151,6 @@ def test_pixel_group(): assert_allclose(pixel_group.array, array[index]) -def test_indexing_bounds(): - pic = novice.open(SMALL_IMAGE_PATH) - - # Outside bounds - assert_raises(IndexError, lambda: pic[pic.width, pic.height]) - - # Negative indexing not supported - assert_raises(IndexError, lambda: pic[-1, -1]) - assert_raises(IndexError, lambda: pic[-1:, -1:]) - - # Step sizes > 1 not supported - assert_raises(IndexError, lambda: pic[::2, ::2]) - - # Only 2D indexes supported - assert_raises(IndexError, lambda: pic[1]) - assert_raises(IndexError, lambda: pic[1, 2, 3]) - - def test_slicing(): cut = 40 pic = novice.open(IMAGE_PATH) @@ -214,6 +172,78 @@ def test_slicing(): assert p1.rgb == p2.rgb +@raises(IndexError) +def test_1d_getitem_raises(): + pic = novice.Picture.from_size((1, 1)) + pic[1] + + +@raises(IndexError) +def test_3d_getitem_raises(): + pic = novice.Picture.from_size((1, 1)) + pic[1, 2, 3] + + +@raises(IndexError) +def test_1d_setitem_raises(): + pic = novice.Picture.from_size((1, 1)) + pic[1] = 0 + + +@raises(IndexError) +def test_3d_setitem_raises(): + pic = novice.Picture.from_size((1, 1)) + pic[1, 2, 3] = 0 + + +@raises(IndexError) +def test_getitem_with_step_raises(): + pic = novice.Picture.from_size((3, 3)) + pic[::2, ::2] + + +@raises(IndexError) +def test_negative_index_raises(): + pic = novice.Picture.from_size((1, 1)) + pic[-1, -1] + + +@raises(IndexError) +def test_negative_slice_raises(): + pic = novice.Picture.from_size((1, 1)) + pic[-1:, -1:] + + +@raises(IndexError) +def test_out_of_bounds_indexing(): + pic = novice.open(SMALL_IMAGE_PATH) + pic[pic.width, pic.height] + + +@raises(ValueError) +def test_pixel_rgb_raises(): + pixel = novice.Picture.from_size((1, 1))[0, 0] + pixel.rgb = (-1, -1, -1) + + +@raises(ValueError) +def test_pixel_red_raises(): + pixel = novice.Picture.from_size((1, 1))[0, 0] + pixel.red = 256 + + +@raises(ValueError) +def test_pixel_green_raises(): + pixel = novice.Picture.from_size((1, 1))[0, 0] + pixel.green = 256 + + +@raises(ValueError) +def test_pixel_blue_raises(): + pixel = novice.Picture.from_size((1, 1))[0, 0] + pixel.blue = 256 + + if __name__ == '__main__': from numpy import testing testing.run_module_suite() From 72c1f6855a1c51ab04fb36d7190479a7ea77a915 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 27 Sep 2013 23:14:13 -0500 Subject: [PATCH 26/51] Rename for clarity --- skimage/novice/_novice.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 3ba45d37..388724c6 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -143,8 +143,8 @@ class PixelGroup(object): def __init__(self, pic, key): self._pic = pic - # Use a slice so that the _getdim and _setdim functions can index - # consistently. + # Use a slice so that the _get_channel and _set_channel functions can + # index consistently. if isinstance(key[0], int): key = (slice(key[0], key[0] + 1), key[1]) @@ -176,14 +176,14 @@ class PixelGroup(object): self._array = pic._array[self._key] - shape = self._getdim(0).shape + shape = self._get_channel(0).shape self.size = (shape[1], shape[0]) - def _getdim(self, dim): + def _get_channel(self, dim): """Return a specific dimension out of the raw image data slice.""" return self._array[:, :, dim] - def _setdim(self, dim, value): + def _set_channel(self, dim, value): """Set a specific dimension in the raw image data slice.""" self._array[:, :, dim] = value @@ -194,38 +194,38 @@ class PixelGroup(object): @property def red(self): """The red component of the pixel (0-255).""" - return self._getdim(0).ravel() + return self._get_channel(0).ravel() @red.setter def red(self, value): - self._setdim(0, value) + self._set_channel(0, value) @property def green(self): """The green component of the pixel (0-255).""" - return self._getdim(1).ravel() + return self._get_channel(1).ravel() @green.setter def green(self, value): - self._setdim(1, value) + self._set_channel(1, value) @property def blue(self): """The blue component of the pixel (0-255).""" - return self._getdim(2).ravel() + return self._get_channel(2).ravel() @blue.setter def blue(self, value): - self._setdim(2, value) + self._set_channel(2, value) @property def rgb(self): """The RGB color components of the pixel (3 values 0-255).""" - return self._getdim(None) + return self._get_channel(None) @rgb.setter def rgb(self, value): - self._setdim(None, value) + self._set_channel(None, value) def __iter__(self): """Iterates through all pixels in the pixel group. From e83003c45d45bc8d420a11f5582380b853bcadef Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 27 Sep 2013 23:27:20 -0500 Subject: [PATCH 27/51] Simplify indexing --- skimage/novice/_novice.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 388724c6..f3112c3d 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -448,8 +448,7 @@ class Picture(object): if isinstance(value, tuple): self[key].rgb = value elif isinstance(value, PixelGroup): - src_key = self[key]._key - self.array[src_key] = value._array + self.array[key[::-1]] = value._array else: raise TypeError("Invalid value type") self._array_modified() From b50d46b3334801da5631b90d4c7ce1d0019d53e2 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 27 Sep 2013 23:42:46 -0500 Subject: [PATCH 28/51] Change PixelGroup to inherit from Picture --- skimage/novice/_novice.py | 219 ++++++++++++++++++-------------------- 1 file changed, 106 insertions(+), 113 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index f3112c3d..db669663 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -129,119 +129,6 @@ class Pixel(object): return "Pixel (red: {0}, green: {1}, blue: {2})".format(*args) -class PixelGroup(object): - """A group of Pixel objects that can be manipulated together. - - Attributes - ---------- - pic : Picture - The Picture object that this pixel group references. - key : tuple - tuple with x and y slices or ints for extracting part of raw image data. - - """ - def __init__(self, pic, key): - self._pic = pic - - # Use a slice so that the _get_channel and _set_channel functions can - # index consistently. - if isinstance(key[0], int): - key = (slice(key[0], key[0] + 1), key[1]) - - if isinstance(key[1], int): - key = (key[0], slice(key[1], key[1] + 1)) - - for dim_slice in key: - if dim_slice.start is not None and dim_slice.start < 0: - raise IndexError("Negative slicing not supported") - - if dim_slice.stop is not None and dim_slice.stop < 0: - raise IndexError("Negative slicing not supported") - - if dim_slice.step is not None and dim_slice.step != 1: - raise IndexError("Only a step size of 1 is supported") - - # Flip y axis - y_slice = key[1] - start = y_slice.start if y_slice.start is not None else 0 - stop = y_slice.stop if y_slice.stop is not None else pic.height - - start = pic.height - start - 1 - stop = pic.height - stop - - key = (key[0], slice(stop, start + 1, y_slice.step)) - - # array dimensions are row, column (i.e. y, x) - self._key = (key[1], key[0]) - - self._array = pic._array[self._key] - - shape = self._get_channel(0).shape - self.size = (shape[1], shape[0]) - - def _get_channel(self, dim): - """Return a specific dimension out of the raw image data slice.""" - return self._array[:, :, dim] - - def _set_channel(self, dim, value): - """Set a specific dimension in the raw image data slice.""" - self._array[:, :, dim] = value - - @property - def array(self): - return self._array - - @property - def red(self): - """The red component of the pixel (0-255).""" - return self._get_channel(0).ravel() - - @red.setter - def red(self, value): - self._set_channel(0, value) - - @property - def green(self): - """The green component of the pixel (0-255).""" - return self._get_channel(1).ravel() - - @green.setter - def green(self, value): - self._set_channel(1, value) - - @property - def blue(self): - """The blue component of the pixel (0-255).""" - return self._get_channel(2).ravel() - - @blue.setter - def blue(self, value): - self._set_channel(2, value) - - @property - def rgb(self): - """The RGB color components of the pixel (3 values 0-255).""" - return self._get_channel(None) - - @rgb.setter - def rgb(self, value): - self._set_channel(None, value) - - def __iter__(self): - """Iterates through all pixels in the pixel group. - - """ - x_idx = range(self._pic.width)[self._key[0]] - y_idx = range(self._pic.height)[self._key[1]] - - for x in x_idx: - for y in y_idx: - yield self._pic._makepixel(x, y) - - def __repr__(self): - return "PixelGroup ({0} pixels)".format(self.size[0] * self.size[1]) - - class Picture(object): """A 2-D picture made up of pixels. @@ -456,3 +343,109 @@ class Picture(object): def __repr__(self): args = self.format, self.path, self.modified return "Picture (format: {0}, path: {1}, modified: {2})".format(*args) + + +class PixelGroup(Picture): + """A group of Pixel objects that can be manipulated together. + + Attributes + ---------- + pic : Picture + The Picture object that this pixel group references. + key : tuple + tuple with x and y slices or ints for extracting part of raw image data. + + """ + def __init__(self, pic, key): + self._pic = pic + + # Use a slice so that the _get_channel and _set_channel functions can + # index consistently. + if isinstance(key[0], int): + key = (slice(key[0], key[0] + 1), key[1]) + + if isinstance(key[1], int): + key = (key[0], slice(key[1], key[1] + 1)) + + for dim_slice in key: + if dim_slice.start is not None and dim_slice.start < 0: + raise IndexError("Negative slicing not supported") + + if dim_slice.stop is not None and dim_slice.stop < 0: + raise IndexError("Negative slicing not supported") + + if dim_slice.step is not None and dim_slice.step != 1: + raise IndexError("Only a step size of 1 is supported") + + # Flip y axis + y_slice = key[1] + start = y_slice.start if y_slice.start is not None else 0 + stop = y_slice.stop if y_slice.stop is not None else pic.height + + start = pic.height - start - 1 + stop = pic.height - stop + + key = (key[0], slice(stop, start + 1, y_slice.step)) + + # array dimensions are row, column (i.e. y, x) + self._key = (key[1], key[0]) + + self._array = pic._array[self._key] + + def _get_channel(self, dim): + """Return a specific dimension out of the raw image data slice.""" + return self._array[:, :, dim] + + def _set_channel(self, dim, value): + """Set a specific dimension in the raw image data slice.""" + self._array[:, :, dim] = value + + @property + def red(self): + """The red component of the pixel (0-255).""" + return self._get_channel(0).ravel() + + @red.setter + def red(self, value): + self._set_channel(0, value) + + @property + def green(self): + """The green component of the pixel (0-255).""" + return self._get_channel(1).ravel() + + @green.setter + def green(self, value): + self._set_channel(1, value) + + @property + def blue(self): + """The blue component of the pixel (0-255).""" + return self._get_channel(2).ravel() + + @blue.setter + def blue(self, value): + self._set_channel(2, value) + + @property + def rgb(self): + """The RGB color components of the pixel (3 values 0-255).""" + return self._get_channel(None) + + @rgb.setter + def rgb(self, value): + self._set_channel(None, value) + + def __iter__(self): + """Iterates through all pixels in the pixel group. + + """ + x_idx = range(self._pic.width)[self._key[0]] + y_idx = range(self._pic.height)[self._key[1]] + + for x in x_idx: + for y in y_idx: + yield self._pic._makepixel(x, y) + + def __repr__(self): + return "PixelGroup ({0} pixels)".format(self.size[0] * self.size[1]) From 12e2a2543e4af2b6a52e762a6faf77a4cf8c739a Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 27 Sep 2013 23:43:49 -0500 Subject: [PATCH 29/51] Move methods from PixelGroup to Picture parent class --- skimage/novice/_novice.py | 88 +++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index db669663..8a316187 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -314,6 +314,50 @@ class Picture(object): new_size = (self.height * self.scale, self.width * self.scale) return img_as_ubyte(resize(array, new_size, order=0)) + def _get_channel(self, dim): + """Return a specific dimension out of the raw image data slice.""" + return self._array[:, :, dim] + + def _set_channel(self, dim, value): + """Set a specific dimension in the raw image data slice.""" + self._array[:, :, dim] = value + + @property + def red(self): + """The red component of the pixel (0-255).""" + return self._get_channel(0).ravel() + + @red.setter + def red(self, value): + self._set_channel(0, value) + + @property + def green(self): + """The green component of the pixel (0-255).""" + return self._get_channel(1).ravel() + + @green.setter + def green(self, value): + self._set_channel(1, value) + + @property + def blue(self): + """The blue component of the pixel (0-255).""" + return self._get_channel(2).ravel() + + @blue.setter + def blue(self, value): + self._set_channel(2, value) + + @property + def rgb(self): + """The RGB color components of the pixel (3 values 0-255).""" + return self._get_channel(None) + + @rgb.setter + def rgb(self, value): + self._set_channel(None, value) + def __iter__(self): """Iterates over all pixels in the image.""" for x in xrange(self.width): @@ -392,50 +436,6 @@ class PixelGroup(Picture): self._array = pic._array[self._key] - def _get_channel(self, dim): - """Return a specific dimension out of the raw image data slice.""" - return self._array[:, :, dim] - - def _set_channel(self, dim, value): - """Set a specific dimension in the raw image data slice.""" - self._array[:, :, dim] = value - - @property - def red(self): - """The red component of the pixel (0-255).""" - return self._get_channel(0).ravel() - - @red.setter - def red(self, value): - self._set_channel(0, value) - - @property - def green(self): - """The green component of the pixel (0-255).""" - return self._get_channel(1).ravel() - - @green.setter - def green(self, value): - self._set_channel(1, value) - - @property - def blue(self): - """The blue component of the pixel (0-255).""" - return self._get_channel(2).ravel() - - @blue.setter - def blue(self, value): - self._set_channel(2, value) - - @property - def rgb(self): - """The RGB color components of the pixel (3 values 0-255).""" - return self._get_channel(None) - - @rgb.setter - def rgb(self, value): - self._set_channel(None, value) - def __iter__(self): """Iterates through all pixels in the pixel group. From a5ad214c4b784a9b2ff54ee6a43d992537df2cd1 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 27 Sep 2013 23:58:38 -0500 Subject: [PATCH 30/51] Move key validation for clarity --- skimage/novice/_novice.py | 44 +++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 8a316187..045c5259 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -27,6 +27,28 @@ def _verify_picture_index(index): if not (isinstance(index, tuple) and len(index) == 2): raise IndexError("Expected 2D index but got {!r}".format(index)) + if all(isinstance(i, int) for i in index): + return index + + # In case we need to fix the array index, convert tuple to list. + index = list(index) + + for i, dim_slice in enumerate(index): + # If either index is a slice, ensure index object returns 2D array. + if isinstance(dim_slice, int): + index[i] = dim_slice = slice(dim_slice, dim_slice + 1) + + if dim_slice.start is not None and dim_slice.start < 0: + raise IndexError("Negative slicing not supported") + + if dim_slice.stop is not None and dim_slice.stop < 0: + raise IndexError("Negative slicing not supported") + + if dim_slice.step is not None and dim_slice.step != 1: + raise IndexError("Only a step size of 1 is supported") + + return tuple(index) + class Pixel(object): """A single pixel in a Picture. @@ -366,7 +388,7 @@ class Picture(object): def __getitem__(self, key): """Return `PixelGroup`s for slices and `Pixel`s for indexes.""" - _verify_picture_index(key) + key = _verify_picture_index(key) if all(isinstance(index, int) for index in key): if any(index < 0 for index in key): raise IndexError("Negative indices not supported") @@ -375,7 +397,7 @@ class Picture(object): return PixelGroup(self, key) def __setitem__(self, key, value): - _verify_picture_index(key) + key = _verify_picture_index(key) if isinstance(value, tuple): self[key].rgb = value elif isinstance(value, PixelGroup): @@ -403,24 +425,6 @@ class PixelGroup(Picture): def __init__(self, pic, key): self._pic = pic - # Use a slice so that the _get_channel and _set_channel functions can - # index consistently. - if isinstance(key[0], int): - key = (slice(key[0], key[0] + 1), key[1]) - - if isinstance(key[1], int): - key = (key[0], slice(key[1], key[1] + 1)) - - for dim_slice in key: - if dim_slice.start is not None and dim_slice.start < 0: - raise IndexError("Negative slicing not supported") - - if dim_slice.stop is not None and dim_slice.stop < 0: - raise IndexError("Negative slicing not supported") - - if dim_slice.step is not None and dim_slice.step != 1: - raise IndexError("Only a step size of 1 is supported") - # Flip y axis y_slice = key[1] start = y_slice.start if y_slice.start is not None else 0 From cedfa8c7d466faa98fff50afac08cc96eaf4a44c Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 00:09:49 -0500 Subject: [PATCH 31/51] Make xy_array public --- skimage/novice/_novice.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 045c5259..28782240 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -50,6 +50,15 @@ def _verify_picture_index(index): return tuple(index) +def cartesian_image_transform(image): + """Return image transformed between array origin and Cartesian origin. + + This transform converts an RGB image's origin from the top-left to the + bottom-left, and switches from (row, column)-indexes to (x, y)-indexes. + """ + return np.transpose(image[::-1], (1, 0, 2)) + + class Pixel(object): """A single pixel in a Picture. @@ -143,7 +152,7 @@ class Pixel(object): NOTE: Using Cartesian coordinate system! """ - self._picture._xy_array[self._x, self._y] = self.rgb + self._picture.xy_array[self._x, self._y] = self.rgb self._picture._array_modified() def __repr__(self): @@ -243,9 +252,16 @@ class Picture(object): @array.setter def array(self, array): self._array = array - # Keep a view of the array with origin at lower-right corner. - # Transpose axis 0 and 1, and leave RGB channels unchanged. - self._xy_array = np.transpose(array[::-1], (1, 0, 2)) + self._xy_array = cartesian_image_transform(array) + + @property + def xy_array(self): + return self._xy_array + + @xy_array.setter + def xy_array(self, array): + self._xy_array = array + self._array = cartesian_image_transform(array) def save(self, path): """Saves the picture to the given path. @@ -283,7 +299,7 @@ class Picture(object): @property def size(self): """The size (width, height) of the picture.""" - return self._xy_array.shape[:2] + return self.xy_array.shape[:2] @size.setter def size(self, value): @@ -326,7 +342,7 @@ class Picture(object): def _makepixel(self, x, y): """Create a Pixel object for a given x, y location.""" - rgb = self._xy_array[x, y] + rgb = self.xy_array[x, y] return Pixel(self, self.array, x, y, rgb) def _rescale(self, array): From 19a9e72ec717f85a0e76597a9277ea68be42e01d Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 12:25:12 -0500 Subject: [PATCH 32/51] Remove PixelGroup dependence on pic and key attrs --- skimage/novice/_novice.py | 17 ++++--------- skimage/novice/tests/test_novice.py | 39 +++++++++++++++++------------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 28782240..4a986bf8 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -439,8 +439,6 @@ class PixelGroup(Picture): """ def __init__(self, pic, key): - self._pic = pic - # Flip y axis y_slice = key[1] start = y_slice.start if y_slice.start is not None else 0 @@ -451,21 +449,16 @@ class PixelGroup(Picture): key = (key[0], slice(stop, start + 1, y_slice.step)) - # array dimensions are row, column (i.e. y, x) - self._key = (key[1], key[0]) - - self._array = pic._array[self._key] + self.array = pic._array[(key[1], key[0])] def __iter__(self): """Iterates through all pixels in the pixel group. """ - x_idx = range(self._pic.width)[self._key[0]] - y_idx = range(self._pic.height)[self._key[1]] - - for x in x_idx: - for y in y_idx: - yield self._pic._makepixel(x, y) + height, width, channels = self.array.shape + for x in range(width): + for y in range(height): + yield self._makepixel(x, y) def __repr__(self): return "PixelGroup ({0} pixels)".format(self.size[0] * self.size[1]) diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 983b7e00..40671d39 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -11,6 +11,10 @@ IMAGE_PATH = os.path.join(data_dir, "elephant.png") SMALL_IMAGE_PATH = os.path.join(data_dir, "block.png") +def _array_2d_to_RGB(array): + return np.tile(array[:, :, np.newaxis], (1, 1, 3)) + + def test_pic_info(): pic = novice.open(IMAGE_PATH) assert_equal(pic.format, "png") @@ -144,32 +148,35 @@ def test_indexing(): def test_pixel_group(): - array = np.tile(np.arange(0, 10)[np.newaxis, :, np.newaxis], (1, 1, 3)) + array = _array_2d_to_RGB(np.arange(0, 10)[np.newaxis, :]) pic = novice.Picture(array=array) - index = (slice(None), slice(3, 8)) - pixel_group = pic[index[::-1]] - assert_allclose(pixel_group.array, array[index]) + + x_slice = slice(3, 8) + pixel_group = pic[:, x_slice] + assert_allclose(pixel_group.array, array[x_slice, :]) def test_slicing(): - cut = 40 - pic = novice.open(IMAGE_PATH) + h, w = 3, 12 + array = _array_2d_to_RGB(np.linspace(0, 255, h * w).reshape(h, w)) + array = array.astype(np.uint8) + + pic = novice.Picture(array=array) + pic_orig = novice.Picture(array=array.copy()) + + # Move left cut of image to the right side. + cut = 5 rest = pic.width - cut temp = pic[:cut, :] + temp.array = temp.array.copy() pic[:rest, :] = pic[cut:, :] pic[rest:, :] = temp - pic_orig = novice.open(IMAGE_PATH) + for pixel, pixel_orig in zip(pic[rest:, :], pic_orig[:cut, :]): + assert pixel.rgb == pixel_orig.rgb - # Check center line - half_height = int(pic.height/2) - for p1 in pic_orig[rest:, half_height]: - for p2 in pic[:cut, half_height]: - assert p1.rgb == p2.rgb - - for p1 in pic_orig[:cut, half_height]: - for p2 in pic[rest:, half_height]: - assert p1.rgb == p2.rgb + for pixel, pixel_orig in zip(pic[:rest, :], pic_orig[cut:, :]): + assert pixel.rgb == pixel_orig.rgb @raises(IndexError) From 35a9cd40673f780f9bd1c0cb28a62263b9589e04 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 16:24:23 -0500 Subject: [PATCH 33/51] Fix setter for xy_array and reuse. --- skimage/novice/_novice.py | 36 +++++++++++------------------ skimage/novice/tests/test_novice.py | 8 +++++++ 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 4a986bf8..f66c634c 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -50,15 +50,16 @@ def _verify_picture_index(index): return tuple(index) -def cartesian_image_transform(image): - """Return image transformed between array origin and Cartesian origin. - - This transform converts an RGB image's origin from the top-left to the - bottom-left, and switches from (row, column)-indexes to (x, y)-indexes. - """ +def array_to_xy_origin(image): + """Return view of image transformed from array to Cartesian origin.""" return np.transpose(image[::-1], (1, 0, 2)) +def xy_to_array_origin(image): + """Return view of image transformed from Cartesian to array origin.""" + return np.transpose(image[:, ::-1], (1, 0, 2)) + + class Pixel(object): """A single pixel in a Picture. @@ -252,7 +253,7 @@ class Picture(object): @array.setter def array(self, array): self._array = array - self._xy_array = cartesian_image_transform(array) + self._xy_array = array_to_xy_origin(array) @property def xy_array(self): @@ -261,7 +262,7 @@ class Picture(object): @xy_array.setter def xy_array(self, array): self._xy_array = array - self._array = cartesian_image_transform(array) + self._array = xy_to_array_origin(array) def save(self, path): """Saves the picture to the given path. @@ -434,22 +435,11 @@ class PixelGroup(Picture): ---------- pic : Picture The Picture object that this pixel group references. - key : tuple - tuple with x and y slices or ints for extracting part of raw image data. - + xy_slice : tuple + 2D slice of `pic` in Cartesian coordinates. """ - def __init__(self, pic, key): - # Flip y axis - y_slice = key[1] - start = y_slice.start if y_slice.start is not None else 0 - stop = y_slice.stop if y_slice.stop is not None else pic.height - - start = pic.height - start - 1 - stop = pic.height - stop - - key = (key[0], slice(stop, start + 1, y_slice.step)) - - self.array = pic._array[(key[1], key[0])] + def __init__(self, pic, xy_slice): + self.xy_array = pic.xy_array[xy_slice] def __iter__(self): """Iterates through all pixels in the pixel group. diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 40671d39..6d9ef4d7 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -4,6 +4,7 @@ import tempfile import numpy as np from numpy.testing import assert_equal, raises, assert_allclose from skimage import novice +from skimage.novice._novice import array_to_xy_origin, xy_to_array_origin from skimage import data_dir @@ -15,6 +16,13 @@ def _array_2d_to_RGB(array): return np.tile(array[:, :, np.newaxis], (1, 1, 3)) +def test_xy_to_array_origin(): + h, w = 3, 5 + array = np.arange(h * w).reshape(h, w, 1) + out = xy_to_array_origin(array_to_xy_origin(array.copy())) + assert np.allclose(out, array) + + def test_pic_info(): pic = novice.open(IMAGE_PATH) assert_equal(pic.format, "png") From 59375f22405c8a51614a343add1af2612548bcfd Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 16:28:17 -0500 Subject: [PATCH 34/51] Rename for clarity --- skimage/novice/_novice.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index f66c634c..ebdfc2bc 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -403,22 +403,22 @@ class Picture(object): for y in xrange(self.height): yield self._makepixel(x, y) - def __getitem__(self, key): + def __getitem__(self, xy_index): """Return `PixelGroup`s for slices and `Pixel`s for indexes.""" - key = _verify_picture_index(key) - if all(isinstance(index, int) for index in key): - if any(index < 0 for index in key): + xy_index = _verify_picture_index(xy_index) + if all(isinstance(index, int) for index in xy_index): + if any(index < 0 for index in xy_index): raise IndexError("Negative indices not supported") - return self._makepixel(*key) + return self._makepixel(*xy_index) else: - return PixelGroup(self, key) + return PixelGroup(self, xy_index) - def __setitem__(self, key, value): - key = _verify_picture_index(key) + def __setitem__(self, xy_index, value): + xy_index = _verify_picture_index(xy_index) if isinstance(value, tuple): - self[key].rgb = value + self[xy_index].rgb = value elif isinstance(value, PixelGroup): - self.array[key[::-1]] = value._array + self.xy_array[xy_index] = value.xy_array else: raise TypeError("Invalid value type") self._array_modified() From f1e01977530b6d2be179b9f1415708b66e9c8bda Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 16:40:53 -0500 Subject: [PATCH 35/51] Remove PixelGroup and just return a Picture --- skimage/novice/_novice.py | 56 +++++++++-------------------- skimage/novice/tests/test_novice.py | 6 ++-- 2 files changed, 19 insertions(+), 43 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index ebdfc2bc..67599e5f 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -202,7 +202,7 @@ class Picture(object): Get the top row of the picture >>> pic[:, pic.height-1] - PixelGroup (100 pixels) + Picture (100 pixels) Set the bottom-left pixel to black >>> pic[0, 0] = (0, 0, 0) @@ -211,22 +211,24 @@ class Picture(object): >>> pic[:, pic.height-1] = (255, 0, 0) """ - def __init__(self, path=None, array=None): - if path is not None and array is not None: - ValueError("Only provide path or array not both.") + def __init__(self, path=None, array=None, xy_array=None): + self._modified = False + self.scale = 1 + self._path = None + self._format = None + + n_args = len([a for a in [path, array, xy_array] if a is not None]) + if n_args != 1: + msg = "Must provide a single keyword arg (path, array, xy_array)." + ValueError(msg) elif path is not None: self.array = img_as_ubyte(io.imread(path)) self._path = path self._format = imghdr.what(path) elif array is not None: self.array = array - self._path = None - self._format = None - else: - ValueError("Must provide path or array.") - - self._modified = False - self.scale = 1 + elif xy_array is not None: + self.xy_array = xy_array @staticmethod def from_size(size, color='black'): @@ -404,20 +406,20 @@ class Picture(object): yield self._makepixel(x, y) def __getitem__(self, xy_index): - """Return `PixelGroup`s for slices and `Pixel`s for indexes.""" + """Return `Picture`s for slices and `Pixel`s for indexes.""" xy_index = _verify_picture_index(xy_index) if all(isinstance(index, int) for index in xy_index): if any(index < 0 for index in xy_index): raise IndexError("Negative indices not supported") return self._makepixel(*xy_index) else: - return PixelGroup(self, xy_index) + return Picture(xy_array=self.xy_array[xy_index]) def __setitem__(self, xy_index, value): xy_index = _verify_picture_index(xy_index) if isinstance(value, tuple): self[xy_index].rgb = value - elif isinstance(value, PixelGroup): + elif isinstance(value, Picture): self.xy_array[xy_index] = value.xy_array else: raise TypeError("Invalid value type") @@ -426,29 +428,3 @@ class Picture(object): def __repr__(self): args = self.format, self.path, self.modified return "Picture (format: {0}, path: {1}, modified: {2})".format(*args) - - -class PixelGroup(Picture): - """A group of Pixel objects that can be manipulated together. - - Attributes - ---------- - pic : Picture - The Picture object that this pixel group references. - xy_slice : tuple - 2D slice of `pic` in Cartesian coordinates. - """ - def __init__(self, pic, xy_slice): - self.xy_array = pic.xy_array[xy_slice] - - def __iter__(self): - """Iterates through all pixels in the pixel group. - - """ - height, width, channels = self.array.shape - for x in range(width): - for y in range(height): - yield self._makepixel(x, y) - - def __repr__(self): - return "PixelGroup ({0} pixels)".format(self.size[0] * self.size[1]) diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 6d9ef4d7..96db85a8 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -155,13 +155,13 @@ def test_indexing(): assert_equal(p.blue, 255) -def test_pixel_group(): +def test_picture_slice(): array = _array_2d_to_RGB(np.arange(0, 10)[np.newaxis, :]) pic = novice.Picture(array=array) x_slice = slice(3, 8) - pixel_group = pic[:, x_slice] - assert_allclose(pixel_group.array, array[x_slice, :]) + subpic = pic[:, x_slice] + assert_allclose(subpic.array, array[x_slice, :]) def test_slicing(): From 51c3d23b2e2acc00bb8a73a4b7f25816a5d23353 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 16:50:08 -0500 Subject: [PATCH 36/51] Fix doctests and cleanup `repr`s --- skimage/novice/_novice.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 67599e5f..9631f8d7 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -158,7 +158,7 @@ class Pixel(object): def __repr__(self): args = self.red, self.green, self.blue - return "Pixel (red: {0}, green: {1}, blue: {2})".format(*args) + return "Pixel(red={0}, green={1}, blue={2})".format(*args) class Picture(object): @@ -188,7 +188,7 @@ class Picture(object): >>> picture = novice.open(data.data_dir + '/elephant.png') Create a blank 100 pixel wide, 200 pixel tall white image - >>> pic = Picture(size=(100, 200), color=(255, 255, 255)) + >>> pic = Picture.from_size((100, 200), color=(255, 255, 255)) Use numpy to make an RGB byte array (shape is height x width x 3) >>> import numpy as np @@ -198,11 +198,11 @@ class Picture(object): Get the bottom-left pixel >>> pic[0, 0] - Pixel (red: 255, green: 0, blue: 0) + Pixel(red=255, green=0, blue=0) Get the top row of the picture >>> pic[:, pic.height-1] - Picture (100 pixels) + Picture(100 x 1) Set the bottom-left pixel to black >>> pic[0, 0] = (0, 0, 0) @@ -426,5 +426,9 @@ class Picture(object): self._array_modified() def __repr__(self): - args = self.format, self.path, self.modified - return "Picture (format: {0}, path: {1}, modified: {2})".format(*args) + return "Picture({0} x {1})".format(*self.size) + + +if __name__ == '__main__': + import doctest + doctest.testmod() From d177aa6c167a9f5a3820eaa8de5f073686596b73 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 16:57:54 -0500 Subject: [PATCH 37/51] Replace use of elephant pic with Chelsea the cat --- skimage/data/elephant.png | Bin 128401 -> 0 bytes skimage/novice/__init__.py | 8 ++++---- skimage/novice/_novice.py | 2 +- skimage/novice/tests/test_novice.py | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 skimage/data/elephant.png diff --git a/skimage/data/elephant.png b/skimage/data/elephant.png deleted file mode 100644 index d75b0a1fccaa58abdf337a1e7a4fdf64a0816c5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128401 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 from skimage import novice >>> from skimage import data ->>> picture = novice.open(data.data_dir + '/elephant.png') +>>> picture = novice.open(data.data_dir + '/chelsea.png') Pictures know their format >>> print picture.format png ... and where they came from ->>> print picture.path.endswith('elephant.png') +>>> print picture.path.endswith('chelsea.png') True ... and their size >>> print picture.size -(665, 500) +(451, 300) >>> print picture.width -665 +451 Changing `size` resizes the picture. >>> picture.size = (200, 250) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 9631f8d7..17b1613a 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -185,7 +185,7 @@ class Picture(object): Load an image from a file >>> from skimage import novice >>> from skimage import data - >>> picture = novice.open(data.data_dir + '/elephant.png') + >>> picture = novice.open(data.data_dir + '/chelsea.png') Create a blank 100 pixel wide, 200 pixel tall white image >>> pic = Picture.from_size((100, 200), color=(255, 255, 255)) diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 96db85a8..5b8c7bd8 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -8,7 +8,7 @@ from skimage.novice._novice import array_to_xy_origin, xy_to_array_origin from skimage import data_dir -IMAGE_PATH = os.path.join(data_dir, "elephant.png") +IMAGE_PATH = os.path.join(data_dir, "chelsea.png") SMALL_IMAGE_PATH = os.path.join(data_dir, "block.png") @@ -27,9 +27,9 @@ def test_pic_info(): pic = novice.open(IMAGE_PATH) assert_equal(pic.format, "png") assert_equal(pic.path, os.path.abspath(IMAGE_PATH)) - assert_equal(pic.size, (665, 500)) - assert_equal(pic.width, 665) - assert_equal(pic.height, 500) + assert_equal(pic.size, (451, 300)) + assert_equal(pic.width, 451) + assert_equal(pic.height, 300) assert not pic.modified assert_equal(pic.scale, 1) From be1d81f3fc75b0ec23ffd07fc9c24bcc9a56fbf2 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 17:08:58 -0500 Subject: [PATCH 38/51] Simplify interface --- skimage/novice/_novice.py | 17 +++++++++++------ skimage/novice/tests/test_novice.py | 7 ++----- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 17b1613a..d058a708 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -355,13 +355,13 @@ class Picture(object): new_size = (self.height * self.scale, self.width * self.scale) return img_as_ubyte(resize(array, new_size, order=0)) - def _get_channel(self, dim): + def _get_channel(self, channel): """Return a specific dimension out of the raw image data slice.""" - return self._array[:, :, dim] + return self._array[:, :, channel] - def _set_channel(self, dim, value): + def _set_channel(self, channel, value): """Set a specific dimension in the raw image data slice.""" - self._array[:, :, dim] = value + self._array[:, :, channel] = value @property def red(self): @@ -393,11 +393,11 @@ class Picture(object): @property def rgb(self): """The RGB color components of the pixel (3 values 0-255).""" - return self._get_channel(None) + return self.xy_array @rgb.setter def rgb(self, value): - self._set_channel(None, value) + self.xy_array[:] = value def __iter__(self): """Iterates over all pixels in the image.""" @@ -425,6 +425,11 @@ class Picture(object): raise TypeError("Invalid value type") self._array_modified() + def __eq__(self, other): + if not isinstance(other, Picture): + raise NotImplementedError() + return np.all(self.array == other.array) + def __repr__(self): return "Picture({0} x {1})".format(*self.size) diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 5b8c7bd8..685a9131 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -180,11 +180,8 @@ def test_slicing(): pic[:rest, :] = pic[cut:, :] pic[rest:, :] = temp - for pixel, pixel_orig in zip(pic[rest:, :], pic_orig[:cut, :]): - assert pixel.rgb == pixel_orig.rgb - - for pixel, pixel_orig in zip(pic[:rest, :], pic_orig[cut:, :]): - assert pixel.rgb == pixel_orig.rgb + assert pic[rest:, :] == pic_orig[:cut, :] + assert pic[:rest, :] == pic_orig[cut:, :] @raises(IndexError) From 6ca30b08976529185fff04cb42a36bd77b8f93e3 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 17:10:29 -0500 Subject: [PATCH 39/51] Speed up doctest --- skimage/novice/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/novice/__init__.py b/skimage/novice/__init__.py index ace7df47..b9937f51 100644 --- a/skimage/novice/__init__.py +++ b/skimage/novice/__init__.py @@ -42,7 +42,7 @@ True 451 Changing `size` resizes the picture. ->>> picture.size = (200, 250) +>>> picture.size = (45, 30) You can iterate over pixels, which have RGB values between 0 and 255, and know their location in the picture. From 68c188050bbae09c0091800ae6d5fd3a4f4174fd Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 17:17:04 -0500 Subject: [PATCH 40/51] Remove old image reference --- skimage/data/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/skimage/data/__init__.py b/skimage/data/__init__.py index ecd261f7..cea2a9f5 100644 --- a/skimage/data/__init__.py +++ b/skimage/data/__init__.py @@ -200,3 +200,4 @@ def coffee(): """ return load("coffee.png") + From 3c33965b99a83a7e8c5586167f110ee34206984d Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 17:19:34 -0500 Subject: [PATCH 41/51] Add docstring for arrays --- skimage/novice/_novice.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index d058a708..5cdf1c96 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -250,6 +250,7 @@ class Picture(object): @property def array(self): + """Image data stored as numpy array.""" return self._array @array.setter @@ -259,6 +260,7 @@ class Picture(object): @property def xy_array(self): + """Image data stored as numpy array with origin at the bottom-left.""" return self._xy_array @xy_array.setter From 1093139d628e7840920a0268744524c670c1bd86 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 17:21:11 -0500 Subject: [PATCH 42/51] Rename image for clarity. --- skimage/novice/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/novice/__init__.py b/skimage/novice/__init__.py index b9937f51..2c76c2b2 100644 --- a/skimage/novice/__init__.py +++ b/skimage/novice/__init__.py @@ -60,8 +60,8 @@ Pictures can be indexed like arrays >>> picture[0:20, 0:20] = (0, 0, 0) Saving the picture updates the path attribute, format, and modified state. ->>> picture.save('sample-bluegreen.jpg') ->>> print picture.path.endswith('sample-bluegreen.jpg') +>>> picture.save('save-demo.jpg') +>>> print picture.path.endswith('save-demo.jpg') True >>> print picture.format jpeg From 7ba0540ec382b1d8546f6c1268a88935b5d2dafc Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 17:28:08 -0500 Subject: [PATCH 43/51] Simplify docstrings --- skimage/novice/_novice.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 5cdf1c96..2cedda75 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -148,11 +148,6 @@ class Pixel(object): return value def _setpixel(self): - """Sets the actual pixel value in the picture. - - NOTE: Using Cartesian coordinate system! - - """ self._picture.xy_array[self._x, self._y] = self.rgb self._picture._array_modified() @@ -169,16 +164,9 @@ class Picture(object): path : str Path to an image file to load. array : array - Raw RGB image data [0-255] - size : tuple - Size of the empty array to create (width, height). - color : tuple - Color to fill empty array if size is given (red, green, blue) [0-255]. - - Notes - ----- - Cannot provide more than one of 'path' and 'size' and 'array'. - Can only provide 'color' if 'size' provided. + Raw RGB image data [0-255], with origin at top-left. + xy_array : array + Raw RGB image data [0-255], with origin at bottom-left. Examples -------- @@ -274,8 +262,7 @@ class Picture(object): Parameters ---------- path : str - Path to save the picture (with file extension). - + Path (with file extension) where the picture is saved. """ io.imsave(path, self._rescale(self.array)) self._modified = False From 4682f44d42a155e8c000f218dcefb87927e6e56b Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 17:33:52 -0500 Subject: [PATCH 44/51] Ensure that image shows when not run interactively --- skimage/novice/_novice.py | 1 + 1 file changed, 1 insertion(+) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 2cedda75..862b9434 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -331,6 +331,7 @@ class Picture(object): def show(self): """Display the image.""" io.imshow(self._rescale(self.array)) + io.show() def _makepixel(self, x, y): """Create a Pixel object for a given x, y location.""" From 555d245a2f960fe261545aca9703c7cb589b0636 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 17:42:00 -0500 Subject: [PATCH 45/51] Fix display in IPython notebook --- skimage/novice/_novice.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 862b9434..8dcd3785 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -322,11 +322,8 @@ class Picture(object): def height(self, value): self.size = (self.width, value) - def _repr_html_(self): - return io.Image(self._rescale(self.array)) - def _repr_png_(self): - return io.Image(self._rescale(self.array)) + return io.Image(self._rescale(self.array))._repr_png_() def show(self): """Display the image.""" From 0b2103b72c00be109dceb5268043a2d2a155e136 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 17:50:06 -0500 Subject: [PATCH 46/51] Remove extra newline --- skimage/data/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/skimage/data/__init__.py b/skimage/data/__init__.py index cea2a9f5..ecd261f7 100644 --- a/skimage/data/__init__.py +++ b/skimage/data/__init__.py @@ -200,4 +200,3 @@ def coffee(): """ return load("coffee.png") - From 5a7e191f7b2751ede70606c06393cbfbf9f18ec6 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 18:15:54 -0500 Subject: [PATCH 47/51] Fix Python 3 incompatibility --- skimage/color/colorlabel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/color/colorlabel.py b/skimage/color/colorlabel.py index 52b12dfb..70803961 100644 --- a/skimage/color/colorlabel.py +++ b/skimage/color/colorlabel.py @@ -17,7 +17,7 @@ DEFAULT_COLORS = ('red', 'blue', 'yellow', 'magenta', 'green', 'indigo', 'darkorange', 'cyan', 'pink', 'yellowgreen') -color_dict = dict((k, v) for k, v in rgb_colors.__dict__.iteritems() +color_dict = dict((k, v) for k, v in six.iteritems(rgb_colors.__dict__) if isinstance(v, tuple)) From 20ad4bbca9220b7153b03e1bee4215dc32466d6a Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 18:40:43 -0500 Subject: [PATCH 48/51] Fix the same Py3 incompatibility in a different place --- skimage/novice/_novice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 8dcd3785..6c43d73f 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -13,7 +13,7 @@ from skimage._shared import six # Convert colors from `skimage.color` to uint8 and allow access through # dict or a named tuple. color_dict = dict((name, tuple(int(255 * c + 0.5) for c in rgb)) - for name, rgb in color_dict.iteritems()) + for name, rgb in six.iteritems(color_dict)) colors = namedtuple('colors', color_dict.keys())(**color_dict) From 8f506be2eac884a51a7817fb662617e2338f7520 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sat, 28 Sep 2013 19:16:35 -0500 Subject: [PATCH 49/51] Fix Py3 range incompatibilities --- skimage/novice/_novice.py | 4 ++-- skimage/novice/tests/test_novice.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 6c43d73f..767bb22a 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -388,8 +388,8 @@ class Picture(object): def __iter__(self): """Iterates over all pixels in the image.""" - for x in xrange(self.width): - for y in xrange(self.height): + for x in range(self.width): + for y in range(self.height): yield self._makepixel(x, y) def __getitem__(self, xy_index): diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 685a9131..40e572a0 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -67,9 +67,9 @@ def test_modify(): def test_pixel_rgb(): pic = novice.Picture.from_size((3, 3), color=(10, 10, 10)) pixel = pic[0, 0] - pixel.rgb = range(3) + pixel.rgb = np.arange(3) - assert_equal(pixel.rgb, range(3)) + assert_equal(pixel.rgb, np.arange(3)) for i, channel in enumerate((pixel.red, pixel.green, pixel.blue)): assert_equal(channel, i) From 6ce788a5d30fb249a0e5fa142fbda6f40d181d96 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sun, 29 Sep 2013 20:16:29 -0500 Subject: [PATCH 50/51] Add support for negative indexes/slices. --- skimage/novice/_novice.py | 21 ++++++++-------- skimage/novice/tests/test_novice.py | 37 ++++++++++++++++++----------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 767bb22a..72f06855 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -38,26 +38,25 @@ def _verify_picture_index(index): if isinstance(dim_slice, int): index[i] = dim_slice = slice(dim_slice, dim_slice + 1) - if dim_slice.start is not None and dim_slice.start < 0: - raise IndexError("Negative slicing not supported") - - if dim_slice.stop is not None and dim_slice.stop < 0: - raise IndexError("Negative slicing not supported") - if dim_slice.step is not None and dim_slice.step != 1: raise IndexError("Only a step size of 1 is supported") return tuple(index) +def rgb_transpose(array): + """Return RGB array with first 2 axes transposed.""" + return np.transpose(array, (1, 0, 2)) + + def array_to_xy_origin(image): """Return view of image transformed from array to Cartesian origin.""" - return np.transpose(image[::-1], (1, 0, 2)) + return rgb_transpose(image[::-1]) def xy_to_array_origin(image): """Return view of image transformed from Cartesian to array origin.""" - return np.transpose(image[:, ::-1], (1, 0, 2)) + return rgb_transpose(image[:, ::-1]) class Pixel(object): @@ -151,6 +150,10 @@ class Pixel(object): self._picture.xy_array[self._x, self._y] = self.rgb self._picture._array_modified() + def __eq__(self, other): + if isinstance(other, Pixel): + return self.rgb == other.rgb + def __repr__(self): args = self.red, self.green, self.blue return "Pixel(red={0}, green={1}, blue={2})".format(*args) @@ -396,8 +399,6 @@ class Picture(object): """Return `Picture`s for slices and `Pixel`s for indexes.""" xy_index = _verify_picture_index(xy_index) if all(isinstance(index, int) for index in xy_index): - if any(index < 0 for index in xy_index): - raise IndexError("Negative indices not supported") return self._makepixel(*xy_index) else: return Picture(xy_array=self.xy_array[xy_index]) diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 40e572a0..214492b4 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -4,7 +4,8 @@ import tempfile import numpy as np from numpy.testing import assert_equal, raises, assert_allclose from skimage import novice -from skimage.novice._novice import array_to_xy_origin, xy_to_array_origin +from skimage.novice._novice import (array_to_xy_origin, xy_to_array_origin, + rgb_transpose) from skimage import data_dir @@ -164,7 +165,7 @@ def test_picture_slice(): assert_allclose(subpic.array, array[x_slice, :]) -def test_slicing(): +def test_move_slice(): h, w = 3, 12 array = _array_2d_to_RGB(np.linspace(0, 255, h * w).reshape(h, w)) array = array.astype(np.uint8) @@ -184,6 +185,26 @@ def test_slicing(): assert pic[:rest, :] == pic_orig[cut:, :] +def test_negative_index(): + n = 10 + array = _array_2d_to_RGB(np.arange(0, n)[np.newaxis, :]) + # Test both x and y indices. + pic = novice.Picture(array=array) + assert pic[-1, 0] == pic[n - 1, 0] + pic = novice.Picture(array=rgb_transpose(array)) + assert pic[0, -1] == pic[0, n - 1] + + +def test_negative_slice(): + n = 10 + array = _array_2d_to_RGB(np.arange(0, n)[np.newaxis, :]) + # Test both x and y slices. + pic = novice.Picture(array=array) + assert pic[-3:, 0] == pic[n - 3:, 0] + pic = novice.Picture(array=rgb_transpose(array)) + assert pic[0, -3:] == pic[0, n - 3:] + + @raises(IndexError) def test_1d_getitem_raises(): pic = novice.Picture.from_size((1, 1)) @@ -214,18 +235,6 @@ def test_getitem_with_step_raises(): pic[::2, ::2] -@raises(IndexError) -def test_negative_index_raises(): - pic = novice.Picture.from_size((1, 1)) - pic[-1, -1] - - -@raises(IndexError) -def test_negative_slice_raises(): - pic = novice.Picture.from_size((1, 1)) - pic[-1:, -1:] - - @raises(IndexError) def test_out_of_bounds_indexing(): pic = novice.open(SMALL_IMAGE_PATH) From e794aed01227f8ed0756c5167632898ac0fafbd0 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Sun, 29 Sep 2013 20:23:14 -0500 Subject: [PATCH 51/51] Add support for non-unit step --- skimage/novice/_novice.py | 3 --- skimage/novice/tests/test_novice.py | 14 ++++++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/skimage/novice/_novice.py b/skimage/novice/_novice.py index 72f06855..2fc4b280 100644 --- a/skimage/novice/_novice.py +++ b/skimage/novice/_novice.py @@ -38,9 +38,6 @@ def _verify_picture_index(index): if isinstance(dim_slice, int): index[i] = dim_slice = slice(dim_slice, dim_slice + 1) - if dim_slice.step is not None and dim_slice.step != 1: - raise IndexError("Only a step size of 1 is supported") - return tuple(index) diff --git a/skimage/novice/tests/test_novice.py b/skimage/novice/tests/test_novice.py index 214492b4..80065e46 100644 --- a/skimage/novice/tests/test_novice.py +++ b/skimage/novice/tests/test_novice.py @@ -205,6 +205,14 @@ def test_negative_slice(): assert pic[0, -3:] == pic[0, n - 3:] +def test_getitem_with_step(): + h, w = 5, 5 + array = _array_2d_to_RGB(np.linspace(0, 255, h * w).reshape(h, w)) + pic = novice.Picture(array=array) + sliced_pic = pic[::2, ::2] + assert sliced_pic == novice.Picture(array=array[::2, ::2]) + + @raises(IndexError) def test_1d_getitem_raises(): pic = novice.Picture.from_size((1, 1)) @@ -229,12 +237,6 @@ def test_3d_setitem_raises(): pic[1, 2, 3] = 0 -@raises(IndexError) -def test_getitem_with_step_raises(): - pic = novice.Picture.from_size((3, 3)) - pic[::2, ::2] - - @raises(IndexError) def test_out_of_bounds_indexing(): pic = novice.open(SMALL_IMAGE_PATH)