{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import imageio\n", "import math" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def rgb2gray(rgb):\n", " return np.dot(rgb[..., :3], [0.299, 0.587, 0.114]).astype(np.uint8)\n", "\n", "\n", "def hough_line(img, angle_step=1, lines_are_white=True, value_threshold=5):\n", " \"\"\"\n", " Hough transform for lines\n", "\n", " Input:\n", " img - 2D binary image with nonzeros representing edges\n", " angle_step - Spacing between angles to use every n-th angle\n", " between -90 and 90 degrees. Default step is 1.\n", " lines_are_white - boolean indicating whether lines to be detected are white\n", " value_threshold - Pixel values above or below the value_threshold are edges\n", "\n", " Returns:\n", " accumulator - 2D array of the hough transform accumulator\n", " theta - array of angles used in computation, in radians.\n", " rhos - array of rho values. Max size is 2 times the diagonal\n", " distance of the input image.\n", " \"\"\"\n", " # Rho and Theta ranges\n", " thetas = np.deg2rad(np.arange(-90.0, 90.0, angle_step))\n", " width, height = img.shape\n", " diag_len = int(round(math.sqrt(width * width + height * height)))\n", " rhos = np.linspace(-diag_len, diag_len, diag_len * 2)\n", "\n", " # Cache some resuable values\n", " cos_t = np.cos(thetas)\n", " sin_t = np.sin(thetas)\n", " num_thetas = len(thetas)\n", "\n", " # Hough accumulator array of theta vs rho\n", " accumulator = np.zeros((2 * diag_len, num_thetas), dtype=np.uint8)\n", " # (row, col) indexes to edges\n", " are_edges = img > value_threshold if lines_are_white else img < value_threshold\n", " y_idxs, x_idxs = np.nonzero(are_edges)\n", "\n", " # Vote in the hough accumulator\n", " for i in range(len(x_idxs)):\n", " x = x_idxs[i]\n", " y = y_idxs[i]\n", "\n", " for t_idx in range(num_thetas):\n", " # Calculate rho. diag_len is added for a positive index\n", " rho = diag_len + int(round(x * cos_t[t_idx] + y * sin_t[t_idx]))\n", " accumulator[rho, t_idx] += 1\n", "\n", " return accumulator, thetas, rhos" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def show_hough_line(img, accumulator, thetas, rhos, save_path=None):\n", " import matplotlib.pyplot as plt\n", "\n", " fig, ax = plt.subplots(1, 2, figsize=(10, 10))\n", "\n", " ax[0].imshow(img, cmap=plt.cm.gray)\n", " ax[0].set_title('Input image')\n", " ax[0].axis('image')\n", "\n", " ax[1].imshow(\n", " accumulator, cmap='jet',\n", " extent=[np.rad2deg(thetas[-1]), np.rad2deg(thetas[0]), rhos[-1], rhos[0]])\n", " ax[1].set_aspect('equal', adjustable='box')\n", " ax[1].set_title('Hough transform')\n", " ax[1].set_xlabel('Angles (degrees)')\n", " ax[1].set_ylabel('Distance (pixels)')\n", " ax[1].axis('image')\n", "\n", " # plt.axis('off')\n", " if save_path is not None:\n", " plt.savefig(save_path, bbox_inches='tight')\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "imgpath = '../images/bangdiem.png'\n", "img = imageio.imread(imgpath)\n", "if img.ndim == 3:\n", " img = rgb2gray(img)\n", "accumulator, thetas, rhos = hough_line(img)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.2" } }, "nbformat": 4, "nbformat_minor": 2 }