{
    "version": "https:\/\/jsonfeed.org\/version\/1",
    "title": "LEFT JOIN: blog on analytics, visualisation & data science, posts tagged: skimage",
    "home_page_url": "https:\/\/en.leftjoin.ru\/tags\/skimage\/",
    "feed_url": "https:\/\/en.leftjoin.ru\/tags\/skimage\/json\/",
    "icon": "https:\/\/en.leftjoin.ru\/user\/userpic@2x.jpg",
    "author": {
        "name": "Nikolay Valiotti",
        "url": "https:\/\/en.leftjoin.ru\/",
        "avatar": "https:\/\/en.leftjoin.ru\/user\/userpic@2x.jpg"
    },
    "items": [
        {
            "id": "31",
            "url": "https:\/\/en.leftjoin.ru\/all\/qr-code-recognition-for-sales-receipts-with-skimage\/",
            "title": "QR code recognition for sales receipts with Skimage",
            "content_html": "<p>When we want to scan a QR code the image quality matters, and oftentimes the image may look blurred and defocused. To address this problem and suppress unwanted distortions we can use image pre-processing. In today’s article we will discover how to improve QR code recognition with the help of <span class=\"inline-code\">scikit-image<\/span>  library.<\/p>\n<pre class=\"e2-text-code\"><code>from matplotlib import pyplot as plt\r\nimport skimage\r\nfrom skimage import util, exposure, io, measure, feature\r\nfrom scipy import ndimage as ndi\r\nimport numpy as np\r\nimport cv2<\/code><\/pre><h2>Subject<\/h2>\n<p>Let’s try to scan this till receipt from our preceding article <a href=\"https:\/\/www.valiotti.com\/leftjoin\/all\/collecting-receipts-with-python-p1\/\/\" class=\"nu\">“<u>Collecting data from hypermarket receipts on Python<\/u>”<\/a>. Use the  <span class=\"inline-code\">imread()<\/span> function to read our image and then display it.<\/p>\n<pre class=\"e2-text-code\"><code>img = plt.imread('чек.jpg')\r\nplt.imshow(img)<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/en.leftjoin.ru\/pictures\/1-1.jpg\" width=\"273\" height=\"252\" alt=\"\" \/>\n<\/div>\n<p>It seems hardly possible to read any letter from this blurred image. Let’s try to do this again with a predefined function from the  <span class=\"inline-code\">opencv<\/span> library:<\/p>\n<pre class=\"e2-text-code\"><code>def qr_reader(img):\r\n    detector = cv2.QRCodeDetector()\r\n    data, bbox, _ = detector.detectAndDecode(img)\r\n    if data:\r\n        print(data)\r\n    else:\r\n        print('Ooops! Nothing here...')<\/code><\/pre><p>Scan our image once again:<\/p>\n<pre class=\"e2-text-code\"><code>qr_reader(img)<\/code><\/pre><pre class=\"e2-text-code\"><code>Ooops! Nothing here...<\/code><\/pre><p>That’s not surprising, the abundance of pixels makes it difficult for the scanner to recognize the QR code. Nevertheless, we can simplify the task by specifying the edges of the QR image.<\/p>\n<h2>Solution<\/h2>\n<p>First, let us remove all the unnecessary pixels, find the coordinates of the QR code and pass it to the <span class=\"inline-code\">qr_reader<\/span>  function. First off, remove noise in the image using the <a href=\"https:\/\/docs.scipy.org\/doc\/scipy\/reference\/generated\/scipy.ndimage.median_filter.html\">median filter<\/a> and convert our RGB image to grayscale, as QR-codes are composed of only two colors.<\/p>\n<pre class=\"e2-text-code\"><code>image = ndi.median_filter(util.img_as_float(img), size=9)\r\nimage = skimage.color.rgb2gray(image)\r\nplt.imshow(image, cmap='gray')<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/en.leftjoin.ru\/pictures\/2.jpg\" width=\"273\" height=\"252\" alt=\"\" \/>\n<\/div>\n<p>The median filter blurred our image, and the scattered pixels have become less clear, while the QR code looks much better now. Apply the  <a href=\"https:\/\/scikit-image.org\/docs\/dev\/api\/skimage.exposure.html\">adjust_gamma<\/a> function to our image. This function exponentiates the gamma value of each pixel, less gamma means that the pixel will be closer to white color. We will set <span class=\"inline-code\">gamma<\/span> to 0.5.<\/p>\n<pre class=\"e2-text-code\"><code>pores_gamma = exposure.adjust_gamma(image, gamma=0.5)\r\nplt.imshow(pores_gamma, cmap='gray')<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/en.leftjoin.ru\/pictures\/3.jpg\" width=\"273\" height=\"252\" alt=\"\" \/>\n<\/div>\n<p>We can see clear improvements, the QR code is now much distinct than previously. Let’s take advantage of it and set all pixels with a value of less than 0.3 to 0,  while others to 1.<\/p>\n<pre class=\"e2-text-code\"><code>thresholded = (pores_gamma &lt;= 0.3)\r\nplt.imshow(thresholded, cmap='gray')<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/en.leftjoin.ru\/pictures\/4.jpg\" width=\"273\" height=\"252\" alt=\"\" \/>\n<\/div>\n<p>Now, let’s apply <a href=\"https:\/\/scikit-image.org\/docs\/dev\/auto_examples\/edges\/plot_canny.html\">the Canny filter<\/a> to our <span class=\"inline-code\">thresholded<\/span> image. This filter smoothes the image and calculate the gradients, the edges are where the gradient at maximum. With the increasing sigma parameter, the <span class=\"inline-code\">canny filter<\/span>  stops discerning less clear edges.<\/p>\n<pre class=\"e2-text-code\"><code>edge = feature.canny(thresholded, sigma=6)\r\nplt.imshow(edge)<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/en.leftjoin.ru\/pictures\/5.jpg\" width=\"273\" height=\"252\" alt=\"\" \/>\n<\/div>\n<p>Outline the QR code with the coordinates of the edges. We can calculate them with the <span class=\"inline-code\">find_contours<\/span> method and draw them atop the image. Coordinates are stored in the contours array.<\/p>\n<pre class=\"e2-text-code\"><code>contours = measure.find_contours(edge, 0.5)\r\nplt.imshow(edge)\r\nfor contour in contours:\r\n    plt.plot(contour[:,1], contour[:,0], linewidth=2)<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/en.leftjoin.ru\/pictures\/6.jpg\" width=\"273\" height=\"252\" alt=\"\" \/>\n<\/div>\n<p>We will take minimum and maximum coordinates for X and Y axes, thus drawing a visible rectangle.<\/p>\n<pre class=\"e2-text-code\"><code>positions = np.concatenate(contours, axis=0)\r\nmin_pos_x = int(min(positions[:,1]))\r\nmax_pos_x = int(max(positions[:,1]))\r\nmin_pos_y = int(min(positions[:,0]))\r\nmax_pos_y = int(max(positions[:,0]))<\/code><\/pre><p>Having the coordinates, we can ensquare the code area:<\/p>\n<pre class=\"e2-text-code\"><code>start = (min_pos_x, min_pos_y)\r\nend = (max_pos_x, max_pos_y)\r\ncv2.rectangle(img, start, end, (255, 0, 0), 5)\r\nio.imshow(img)<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/en.leftjoin.ru\/pictures\/7.jpg\" width=\"300\" height=\"280\" alt=\"\" \/>\n<\/div>\n<p>Let’s try to cut this area according to our coordinates:<\/p>\n<pre class=\"e2-text-code\"><code>new_img = img[min_pos_y:max_pos_y, min_pos_x:max_pos_x]\r\nplt.imshow(new_img)<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/en.leftjoin.ru\/pictures\/8.jpg\" width=\"311\" height=\"252\" alt=\"\" \/>\n<\/div>\n<p>Pass the new image to the <span class=\"inline-code\">qr_reader<\/span> function:<\/p>\n<pre class=\"e2-text-code\"><code>qr_reader(new_img)<\/code><\/pre><p>And it returns this:<\/p>\n<pre class=\"e2-text-code\"><code>t=20190320T2303&amp;s=5803.00&amp;fn=9251440300007971&amp;i=141637&amp;fp=4087570038&amp;n=1<\/code><\/pre><p>That’s exactly what we need! Of course, the script is not universal and every image is unique, some may have too much noise or low contrast, while others may not. The sequence of actions depends on the case. Next time, we will show the subsequent stage of image processing using a well-established python library.<\/p>\n",
            "date_published": "2020-06-05T11:27:06+03:00",
            "date_modified": "2020-06-05T11:22:55+03:00",
            "image": "https:\/\/en.leftjoin.ru\/pictures\/1-1.jpg",
            "_date_published_rfc2822": "Fri, 05 Jun 2020 11:27:06 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "31",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/en.leftjoin.ru\/pictures\/1-1.jpg",
                    "https:\/\/en.leftjoin.ru\/pictures\/2.jpg",
                    "https:\/\/en.leftjoin.ru\/pictures\/3.jpg",
                    "https:\/\/en.leftjoin.ru\/pictures\/4.jpg",
                    "https:\/\/en.leftjoin.ru\/pictures\/5.jpg",
                    "https:\/\/en.leftjoin.ru\/pictures\/6.jpg",
                    "https:\/\/en.leftjoin.ru\/pictures\/7.jpg",
                    "https:\/\/en.leftjoin.ru\/pictures\/8.jpg"
                ]
            }
        }
    ],
    "_e2_version": 3386,
    "_e2_ua_string": "E2 (v3386; Aegea)"
}