{"id":175,"date":"2016-02-20T20:30:14","date_gmt":"2016-02-20T20:30:14","guid":{"rendered":"http:\/\/weegreenblobbie.com\/?p=175"},"modified":"2016-02-21T00:23:41","modified_gmt":"2016-02-21T00:23:41","slug":"ranking-photos-with-python","status":"publish","type":"post","link":"http:\/\/weegreenblobbie.com\/?p=175","title":{"rendered":"Ranking Photos With Python"},"content":{"rendered":"<h1>Photo Ranking With Python<\/h1>\n<p><a href=\"https:\/\/github.com\/weegreenblobbie\/rank_photos\/blob\/master\/screenshot.jpg\" target=\"_blank\"><img decoding=\"async\" src=\"https:\/\/github.com\/weegreenblobbie\/rank_photos\/raw\/master\/screenshot.jpg\" alt=\"screenshot.jpg\" \/><\/a><\/p>\n<p><a name=\"user-content-what-is-this\"><\/a><\/p>\n<h2><a id=\"user-content-what-is-this\" class=\"anchor\" href=\"https:\/\/github.com\/weegreenblobbie\/rank_photos#what-is-this\"><\/a>What is this?<\/h2>\n<p>This is a tool that uses the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Elo_rating_system\">Elo Ranking System<\/a> written in Python using:<\/p>\n<ol>\n<li>Matplotlib<\/li>\n<li>Numpy<\/li>\n<li>exifread<\/li>\n<\/ol>\n<p>Features:<\/p>\n<ul>\n<li>Auto image rotation that the camera recored in the EXIF meta data<\/li>\n<li>Persistent state from execution to execution so you can pickup where you left off<\/li>\n<li>New photos that are added to the photo dir after initial ranking are picked up<\/li>\n<\/ul>\n<p><a name=\"user-content-install-dependencies\"><\/a><\/p>\n<h2><a id=\"user-content-install-dependencies\" class=\"anchor\" href=\"https:\/\/github.com\/weegreenblobbie\/rank_photos#install-dependencies\"><\/a>Install dependencies<\/h2>\n<p>Use your system&#8217;s package manager to install Matplotlib &amp; Numpy if you don&#8217;t already have them installed.<\/p>\n<p>Next, you can use pip to install the EXIF image reader package <a href=\"https:\/\/pypi.python.org\/pypi\/ExifRead\">exifread<\/a>:<\/p>\n<div class=\"highlight highlight-source-shell\">\n<pre>pip install exifread --user<\/pre>\n<\/div>\n<p><a name=\"user-content-how-to-rank-photos\"><\/a><\/p>\n<h2><a id=\"user-content-how-to-rank-photos\" class=\"anchor\" href=\"https:\/\/github.com\/weegreenblobbie\/rank_photos#how-to-rank-photos\"><\/a>How to rank photos<\/h2>\n<p>Once you have to dependencies installed, run <code>rank_photos.py<\/code> on the command line passing it the directory of photos.<\/p>\n<div class=\"highlight highlight-source-shell\">\n<pre class=\"\">.\/rank_photos.py -h\r\n\r\nusage: rank_photos.py [-h] [-r N_ROUNDS] [-f FIGSIZE FIGSIZE] photo_dir\r\n\r\nUses the Elo ranking algorithm to sort your images by rank. The program globs\r\nfor .jpg images to present to you in random order, then you select the better\r\nphoto. After n-rounds, the results are reported.\r\n\r\npositional arguments:\r\n  photo_dir             The photo directory to scan for .jpg images\r\n\r\noptional arguments:\r\n  -h, --help            show this help message and exit\r\n  -r N_ROUNDS, --n-rounds N_ROUNDS\r\n                        Specifies the number of rounds to pass through the\r\n                        photo set (3)\r\n  -f FIGSIZE FIGSIZE, --figsize FIGSIZE FIGSIZE\r\n                        Specifies width and height of the Matplotlib figsize\r\n                        (20, 12)<\/pre>\n<\/div>\n<p>For example, iterate over all photos three times:<\/p>\n<div class=\"highlight highlight-source-shell\">\n<pre>.\/rank_photos.py ~\/Desktop\/example\/<\/pre>\n<\/div>\n<p>After the number of rounds complete, <code>ranked.txt<\/code> is written into the photo dir.<\/p>\n<p><a name=\"user-content-ranking-work-is-cached\"><\/a><\/p>\n<h2><a id=\"user-content-ranking-work-is-cached\" class=\"anchor\" href=\"https:\/\/github.com\/weegreenblobbie\/rank_photos#ranking-work-is-cached\"><\/a>Ranking work is cached<\/h2>\n<p>After completing N rounds of ranking, a file called <code>ranking_table.json<\/code> is written into the photo dir. The next time<code>rank_photos.py<\/code> is executed with the photo dir, this table is read in and ranking can continue where you left off.<\/p>\n<p>You can also add new photos the the directory and they will get added to the ranked list even though they weren&#8217;t included previously.<\/p>\n<p><a name=\"user-content-example\"><\/a><\/p>\n<h2><a id=\"user-content-example\" class=\"anchor\" href=\"https:\/\/github.com\/weegreenblobbie\/rank_photos#example\"><\/a>Example<\/h2>\n<p>Suppose there is a dir containing some photos:<\/p>\n<div class=\"highlight highlight-source-shell\">\n<pre>ls -1 ~\/Desktop\/example\/\r\n\r\n20160102_164732.jpg\r\n20160109_151557.jpg\r\n20160109_151607.jpg\r\n20160109_152318.jpg\r\n20160109_152400.jpg\r\n20160109_152414.jpg\r\n20160109_153443.jpg<\/pre>\n<\/div>\n<p>These photos haven&#8217;t been ranked yet, so lets rank them, in this example, 1 round:<\/p>\n<div class=\"highlight highlight-source-shell\">\n<pre>.\/rank_photos.py -r 1 ~\/Desktop\/example\/<\/pre>\n<\/div>\n<p>Once the number of rounds complete, the ranked list is dumped to the console:<\/p>\n<div class=\"highlight highlight-source-shell\">\n<pre>Final Ranking:\r\nRank    Score    Matches    Win %    Filename\r\n   1    1433          2     100.00    20160109_152414.jpg\r\n   2    1414          3      66.67    20160109_151557.jpg\r\n   3    1401          2      50.00    20160109_153443.jpg\r\n   4    1400          2      50.00    20160102_164732.jpg\r\n   5    1387          3      33.33    20160109_151607.jpg\r\n   6    1383          3      33.33    20160109_152318.jpg\r\n   7    1382          3      33.33    20160109_152400.jpg<\/pre>\n<\/div>\n<p>The ranked list is also written to the file <code>ranked.txt<\/code>. The raw data is cached to the file <code>ranking_table.json<\/code>:<\/p>\n<div class=\"highlight highlight-source-shell\">\n<pre class=\"\">cat ~\/Desktop\/example\/ranking_table.json\r\n\r\n{\r\n    \"photos\" : [\r\n        {\r\n            \"matches\" : 2,\r\n            \"wins\" : 2,\r\n            \"score\" : 1432.736306793522,\r\n            \"filename\" : \"20160109_152414.jpg\"\r\n        },\r\n        {\r\n            \"matches\" : 3,\r\n            \"wins\" : 2,\r\n            \"score\" : 1413.760501639972,\r\n            \"filename\" : \"20160109_151557.jpg\"\r\n        },\r\n        {\r\n            \"matches\" : 2,\r\n            \"wins\" : 1,\r\n            \"score\" : 1400.736306793522,\r\n            \"filename\" : \"20160109_153443.jpg\"\r\n        },\r\n        {\r\n            \"matches\" : 2,\r\n            \"wins\" : 1,\r\n            \"score\" : 1400.0336900375303,\r\n            \"filename\" : \"20160102_164732.jpg\"\r\n        },\r\n        {\r\n            \"matches\" : 3,\r\n            \"wins\" : 1,\r\n            \"score\" : 1387.00607880615,\r\n            \"filename\" : \"20160109_151607.jpg\"\r\n        },\r\n        {\r\n            \"matches\" : 3,\r\n            \"wins\" : 1,\r\n            \"score\" : 1383.263693206478,\r\n            \"filename\" : \"20160109_152318.jpg\"\r\n        },\r\n        {\r\n            \"matches\" : 3,\r\n            \"wins\" : 1,\r\n            \"score\" : 1382.4634227228255,\r\n            \"filename\" : \"20160109_152400.jpg\"\r\n        }\r\n    ]\r\n}<\/pre>\n<\/div>\n<p>If you run the program again, the cached data is loaded and new match ups can be continued using the cached data. If new photos were added, they also get added to the table data and are included in match ups.<\/p>\n<p>The code has been posted to <a href=\"https:\/\/github.com\/weegreenblobbie\/rank_photos\">github<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Photo Ranking With Python What is this? This is a tool that uses the Elo Ranking System written in Python using: Matplotlib Numpy exifread Features: Auto image rotation that the camera recored in the EXIF meta data Persistent state from &hellip; <a href=\"http:\/\/weegreenblobbie.com\/?p=175\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,7],"tags":[],"class_list":["post-175","post","type-post","status-publish","format-standard","hentry","category-computing","category-programming"],"_links":{"self":[{"href":"http:\/\/weegreenblobbie.com\/index.php?rest_route=\/wp\/v2\/posts\/175","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/weegreenblobbie.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/weegreenblobbie.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/weegreenblobbie.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/weegreenblobbie.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=175"}],"version-history":[{"count":6,"href":"http:\/\/weegreenblobbie.com\/index.php?rest_route=\/wp\/v2\/posts\/175\/revisions"}],"predecessor-version":[{"id":182,"href":"http:\/\/weegreenblobbie.com\/index.php?rest_route=\/wp\/v2\/posts\/175\/revisions\/182"}],"wp:attachment":[{"href":"http:\/\/weegreenblobbie.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=175"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/weegreenblobbie.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=175"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/weegreenblobbie.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=175"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}