├── .vscode
└── settings.json
├── 01 Connected-component labeling
├── .ipynb_checkpoints
│ └── connected_compoent_labeling-checkpoint.ipynb
├── README.md
├── Rose-BMP.bmp
├── connected_compoent_labeling.ipynb
├── connected_component_labeling.py
└── doc
│ ├── 4-connectivity.png
│ ├── 8-connectivity.png
│ ├── binary_image.png
│ └── origin_image.png
├── 02 Distance transform
├── README.md
├── distance_transform.py
├── doc
│ ├── D4.png
│ ├── D8.png
│ ├── De.png
│ └── origin_image.png
└── paperPhoto2021031918372826.bmp
├── 03 Contrast stretching
├── README.md
├── contrast_stretching.py
├── doc
│ ├── origin_hist1.png
│ ├── origin_hist2.png
│ ├── origin_img1.png
│ ├── origin_img2.png
│ ├── st_hist1.png
│ ├── st_hist2.png
│ ├── st_img1.png
│ └── st_img2.png
├── paperPhoto20210402174743810.bmp
└── paperPhoto20210402174743817.bmp
├── 04 Histogram equalization
├── README.md
├── doc
│ ├── T1.png
│ ├── T2.png
│ ├── eq_hist1.png
│ ├── eq_hist2.png
│ ├── eq_img1.png
│ ├── eq_img2.png
│ ├── origin_hist1.png
│ ├── origin_hist2.png
│ ├── origin_img1.png
│ └── origin_img2.png
├── histogram_equalization.py
├── paperPhoto20210402174743810.bmp
└── paperPhoto20210402174743817.bmp
├── 05 Median filtering
├── README.md
├── doc
│ ├── 3f_hist1.png
│ ├── 3f_hist2.png
│ ├── 3f_img1.png
│ ├── 3f_img2.png
│ ├── 5f_hist1.png
│ ├── 5f_hist2.png
│ ├── 5f_img1.png
│ ├── 5f_img2.png
│ ├── origin_hist1.png
│ ├── origin_hist2.png
│ ├── origin_img1.png
│ └── origin_img2.png
├── median_filtering.py
├── paperPhoto20210402174743810.bmp
└── paperPhoto20210402174743817.bmp
├── 06 Edge Detection
├── README.md
├── doc
│ ├── log_3_1.png
│ ├── log_3_1_thr.png
│ ├── log_3_2.png
│ ├── log_3_2_thr.png
│ ├── log_5.png
│ ├── log_5_thr.png
│ ├── log_9.png
│ ├── log_9_thr.png
│ ├── origin_img.png
│ ├── prewitt_sum.png
│ ├── prewitt_thr.png
│ ├── prewitt_x.png
│ ├── prewitt_y.png
│ ├── roberts_1.png
│ ├── roberts_2.png
│ ├── roberts_sum.png
│ ├── roberts_thr.png
│ ├── sobel_sum.png
│ ├── sobel_thr.png
│ ├── sobel_x.png
│ └── sobel_y.png
├── edge_detection.py
└── lena.png
├── 07 Frequency domain filtering
├── README.md
├── Rose-BMP.bmp
├── doc
│ ├── fft.png
│ ├── fft_shift.png
│ ├── high_pass_filter.png
│ ├── inverse_fft_high.png
│ ├── inverse_fft_low.png
│ ├── inverse_fft_low_r20.png
│ ├── low_pass_filter.png
│ ├── low_pass_filter_r20.png
│ └── origin_img.png
└── frequency_domain_filtering.py
├── 08 Convolution theorem
├── README.md
├── Rose-BMP.bmp
├── convolution_theorem.py
└── doc
│ ├── conv.png
│ ├── fft.png
│ ├── ifft.png
│ ├── img.png
│ ├── mul_fft.png
│ └── sobel_fft.png
├── 09 Hough transform
├── .pylint.d
│ └── untitled21.stats
├── README.md
├── doc
│ ├── fig.png
│ ├── fig_draw_lines.png
│ ├── fig_filter_lines.png
│ ├── fig_houghspace.png
│ ├── fig_select_lines.png
│ ├── test.png
│ ├── test_houghspace.png
│ └── test_line.png
├── fig.png
├── hough_transform.py
└── test.png
└── README.md
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.pythonPath": "C:\\ProgramData\\Anaconda3\\python.exe"
3 | }
--------------------------------------------------------------------------------
/01 Connected-component labeling/README.md:
--------------------------------------------------------------------------------
1 | # Connected-component labeling
2 |
3 | Detail : https://jstar0525.tistory.com/2
4 |
5 | ## Input image
6 |
7 |
8 | ## Thresholded binary image
9 |
10 |
11 | ## Connected-component labeling
12 | ### using 4-connectivity and threshold 10,000 pixel
13 |
14 |
15 | ## Connected-component labeling
16 | ### using 8-connectivity and threshold 10,000 pixel
17 |
18 |
--------------------------------------------------------------------------------
/01 Connected-component labeling/Rose-BMP.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/01 Connected-component labeling/Rose-BMP.bmp
--------------------------------------------------------------------------------
/01 Connected-component labeling/connected_compoent_labeling.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "id": "64cd3e62",
7 | "metadata": {},
8 | "outputs": [],
9 | "source": [
10 | "from PIL import Image\n",
11 | "import numpy as np\n",
12 | "import matplotlib.pyplot as plt"
13 | ]
14 | },
15 | {
16 | "cell_type": "markdown",
17 | "id": "34df22b8",
18 | "metadata": {},
19 | "source": [
20 | "# 1. Conduct a thresholding with a threshold=200"
21 | ]
22 | },
23 | {
24 | "cell_type": "markdown",
25 | "id": "6dba1aa8",
26 | "metadata": {},
27 | "source": [
28 | "## (1) read image"
29 | ]
30 | },
31 | {
32 | "cell_type": "code",
33 | "execution_count": 2,
34 | "id": "5b97ae16",
35 | "metadata": {},
36 | "outputs": [
37 | {
38 | "data": {
39 | "image/png": "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\n",
40 | "text/plain": [
41 | ""
42 | ]
43 | },
44 | "metadata": {
45 | "needs_background": "light"
46 | },
47 | "output_type": "display_data"
48 | }
49 | ],
50 | "source": [
51 | "img = Image.open('Rose-BMP.bmp').convert('L')\n",
52 | "bw_img = np.array(img)\n",
53 | "\n",
54 | "plt.title('Input image')\n",
55 | "plt.imshow(bw_img, cmap='gray')\n",
56 | "plt.show()"
57 | ]
58 | },
59 | {
60 | "cell_type": "markdown",
61 | "id": "82e0d032",
62 | "metadata": {},
63 | "source": [
64 | "## (2) thresholded binary image"
65 | ]
66 | },
67 | {
68 | "cell_type": "code",
69 | "execution_count": 3,
70 | "id": "20df43c1",
71 | "metadata": {},
72 | "outputs": [
73 | {
74 | "data": {
75 | "image/png": "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t28Oisvl0pdfflmTk5MbpUp+++2311jtdrlc+uGHH+q8efO0e/fuvn3uvfdeX5mTJ0/q66+/rpMnT9YzZ86oquqmTZv0sssuq/GcDodDp06dqk8++aQOGDBA+/btq507d652FOqQIUN0zpw5GhERUa97d9ddd2leXp4WFBTonDlz1O126549ezQ1NbVRvp+oqChNS0vTiRMn6qpVq/T777+vdS7Or3/962b/TTV3avImzKWKxWIhISGBBx98kG7durFr1y7mz5/Pgw8+yFdffcWmTZsICwtr8ACp85Gfn0/Hjh3Zs2dPFedgr169fO9DQkLYs2cPEydOJDY2loqKCmbOnFnr2AtVZerUqYSGhhITE8O+ffvYv3//ObUVEWHixInMmTOnzmEDe/fujcVi4b333uO2225j165dhIeHA55Qha+++qovZGFDcDqdhIaGEh8fT6dOndizZ0+N38d3333H66+/3uBzXrI0dw2jNdVAgoODNTw8XOPi4nT06NE6b948/eqrr3TQoEE6ZMgQ7dOnj8bExDTa+WqrgZSXl+uePXv0uuuuq1IDeOWVV3xlioqKdN68eb6JZCtWrNCwsLBaz2mxWHTJkiV64sSJWmsEiYmJev/992tYWJgGBwdr7969z5mDcnYaNWqU3n777b7PnTt31t27d2t+fr6++eabun79en377bfrPEentmS327VXr166bNmyGh3ROTk5OnDgwGb/XbWEFOjzaaKyn4ewsDBuvfVWtm/fzrFjx2jTpg39+/fno48+Yu/evbhcLnJycrDZbLU6GwOhctnI6rparVYrRUVFJCQkYLPZzgnZp6ocOnSIsWPHEhoaSmFhIU888QRFRUW1nlNVyc3NJTExkVGjRjFz5sxqyyUmJrJs2TL++7//m48++ogHHniAjRs3+hzJb7755jk+keXLl3PvvffyyCOP8PLLL3PgwAE2b97M4sWLWbhwIX369OH3v/+9b2GrhlC5mFZQUJBvYXF/CgsL+fWvf813333XoPNc8jR3DaMl10BCQkJ05syZvn/yO+64Q+Pj48/5F2+Mf8zqUlpaWrXT0FVVd+3apc8884wv6lhlN+6vfvUrVVXNzMzUadOm6bFjx1RVdcGCBXXyy4SHh2t6erqqenwoN998c7XXFxcXp1deeaWeOnVKX3vtNU1PT9fy8nJVVd29e3eNNbFR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\n",
76 | "text/plain": [
77 | ""
78 | ]
79 | },
80 | "metadata": {
81 | "needs_background": "light"
82 | },
83 | "output_type": "display_data"
84 | }
85 | ],
86 | "source": [
87 | "bin_img = bw_img.copy()\n",
88 | "\n",
89 | "threshold = 200\n",
90 | "bin_img[bin_img=threshold] = 1\n",
92 | "\n",
93 | "plt.title('Thresholded binary image')\n",
94 | "plt.imshow(bin_img, cmap='gray')\n",
95 | "plt.show()"
96 | ]
97 | },
98 | {
99 | "cell_type": "markdown",
100 | "id": "8b165c98",
101 | "metadata": {},
102 | "source": [
103 | "# 2. Delete all the regions which are less than 10,000"
104 | ]
105 | },
106 | {
107 | "cell_type": "code",
108 | "execution_count": 4,
109 | "id": "708a5348",
110 | "metadata": {},
111 | "outputs": [],
112 | "source": [
113 | "connectivity_4 = np.array([[0,1,0],\n",
114 | " [1,0,0],\n",
115 | " [0,0,0]])\n",
116 | "\n",
117 | "connectivity_8 = np.array([[1,1,1],\n",
118 | " [1,0,0],\n",
119 | " [0,0,0]])"
120 | ]
121 | },
122 | {
123 | "cell_type": "code",
124 | "execution_count": 5,
125 | "id": "ae43f294",
126 | "metadata": {},
127 | "outputs": [],
128 | "source": [
129 | "def find_labels(labels, r, c, neighbors):\n",
130 | " \n",
131 | " tmp_labels = labels[r-1:r+2, c-1:c+2]*neighbors\n",
132 | " \n",
133 | " return np.sort(tmp_labels[np.nonzero(tmp_labels)])\n",
134 | " \n",
135 | "def connected_component_labeling(bin_img, connectivity=connectivity_8):\n",
136 | " \n",
137 | " equivalent = []\n",
138 | " labels = np.zeros_like(bin_img, dtype='int64')\n",
139 | " next_label = 1\n",
140 | " \n",
141 | " # 1st pass\n",
142 | " for r, row in enumerate(bin_img):\n",
143 | " for c, pixel in enumerate(row):\n",
144 | " \n",
145 | " if pixel!=0:\n",
146 | " neighbors = bin_img[r-1:r+2, c-1:c+2]*connectivity\n",
147 | " num_neighbors = np.count_nonzero(neighbors)\n",
148 | " \n",
149 | " if num_neighbors==0:\n",
150 | " labels[r,c] = next_label\n",
151 | " equivalent.append([next_label,next_label])\n",
152 | " next_label += 1\n",
153 | " else:\n",
154 | " L = find_labels(labels, r, c, neighbors)\n",
155 | " labels[r,c] = np.min(L)\n",
156 | " \n",
157 | " uni_L = np.unique(L)\n",
158 | " if len(uni_L)>1:\n",
159 | " for i, e in enumerate(equivalent):\n",
160 | " if uni_L[0] in e:\n",
161 | " equivalent[i].extend(uni_L[1:])\n",
162 | " equivalent[i] = list(sorted(set(equivalent[i]))) \n",
163 | " # 2nd pass\n",
164 | " for e in equivalent:\n",
165 | " for f in reversed(e):\n",
166 | " labels[labels==f] = e[0]\n",
167 | " \n",
168 | " return labels\n",
169 | "\n",
170 | "def threshold_labels(labels, threshold=10000):\n",
171 | " \n",
172 | " unique_elements, counts_elements = np.unique(labels, return_counts=True) \n",
173 | " thr_elements = unique_elements[counts_elements>threshold]\n",
174 | " \n",
175 | " thr_labels = np.zeros_like(labels)\n",
176 | " \n",
177 | " cnt = 0\n",
178 | " for e in thr_elements:\n",
179 | " if e != 0:\n",
180 | " cnt += 1\n",
181 | " thr_labels[labels==e] = cnt\n",
182 | " \n",
183 | " return thr_labels"
184 | ]
185 | },
186 | {
187 | "cell_type": "code",
188 | "execution_count": 6,
189 | "id": "8c65acb8",
190 | "metadata": {},
191 | "outputs": [
192 | {
193 | "data": {
194 | "image/png": "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\n",
195 | "text/plain": [
196 | ""
197 | ]
198 | },
199 | "metadata": {
200 | "needs_background": "light"
201 | },
202 | "output_type": "display_data"
203 | }
204 | ],
205 | "source": [
206 | "labels_4 = connected_component_labeling(bin_img, connectivity_4)\n",
207 | "thr_labels_4 = threshold_labels(labels_4)\n",
208 | "\n",
209 | "plt.title('4-connectivity (threshold)')\n",
210 | "plt.imshow(thr_labels_4)\n",
211 | "plt.show()"
212 | ]
213 | },
214 | {
215 | "cell_type": "code",
216 | "execution_count": 7,
217 | "id": "b359688a",
218 | "metadata": {},
219 | "outputs": [
220 | {
221 | "data": {
222 | "image/png": "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\n",
223 | "text/plain": [
224 | ""
225 | ]
226 | },
227 | "metadata": {
228 | "needs_background": "light"
229 | },
230 | "output_type": "display_data"
231 | }
232 | ],
233 | "source": [
234 | "labels_8 = connected_component_labeling(bin_img, connectivity_8)\n",
235 | "thr_labels_8 = threshold_labels(labels_8)\n",
236 | "\n",
237 | "plt.title('8-connectivity (threshold)')\n",
238 | "plt.imshow(thr_labels_8)\n",
239 | "plt.show()"
240 | ]
241 | },
242 | {
243 | "cell_type": "markdown",
244 | "id": "1dd8663c",
245 | "metadata": {},
246 | "source": [
247 | "# 3. Count the number of remaining regions"
248 | ]
249 | },
250 | {
251 | "cell_type": "code",
252 | "execution_count": 8,
253 | "id": "2d5e0e9e",
254 | "metadata": {},
255 | "outputs": [
256 | {
257 | "name": "stdout",
258 | "output_type": "stream",
259 | "text": [
260 | "4-connectivity\n",
261 | "label : 0\n",
262 | "number of pixel : 1010003\n",
263 | "label : 1\n",
264 | "number of pixel : 16724\n",
265 | "label : 2\n",
266 | "number of pixel : 21849\n"
267 | ]
268 | }
269 | ],
270 | "source": [
271 | "_, counts_elements_4 = np.unique(thr_labels_4, return_counts=True)\n",
272 | "\n",
273 | "print('4-connectivity')\n",
274 | "for l, c in enumerate(counts_elements_4):\n",
275 | " print('label :', l)\n",
276 | " print('number of pixel :', c)"
277 | ]
278 | },
279 | {
280 | "cell_type": "code",
281 | "execution_count": 9,
282 | "id": "be8faa8c",
283 | "metadata": {},
284 | "outputs": [
285 | {
286 | "name": "stdout",
287 | "output_type": "stream",
288 | "text": [
289 | "8-connectivity\n",
290 | "label : 0\n",
291 | "number of pixel : 1008875\n",
292 | "label : 1\n",
293 | "number of pixel : 17103\n",
294 | "label : 2\n",
295 | "number of pixel : 22598\n"
296 | ]
297 | }
298 | ],
299 | "source": [
300 | "_, counts_elements_8 = np.unique(thr_labels_8, return_counts=True)\n",
301 | " \n",
302 | "print('8-connectivity')\n",
303 | "for l, c in enumerate(counts_elements_8):\n",
304 | " print('label :', l)\n",
305 | " print('number of pixel :', c)"
306 | ]
307 | },
308 | {
309 | "cell_type": "code",
310 | "execution_count": null,
311 | "id": "1baeec82",
312 | "metadata": {},
313 | "outputs": [],
314 | "source": []
315 | }
316 | ],
317 | "metadata": {
318 | "kernelspec": {
319 | "display_name": "Python 3",
320 | "language": "python",
321 | "name": "python3"
322 | },
323 | "language_info": {
324 | "codemirror_mode": {
325 | "name": "ipython",
326 | "version": 3
327 | },
328 | "file_extension": ".py",
329 | "mimetype": "text/x-python",
330 | "name": "python",
331 | "nbconvert_exporter": "python",
332 | "pygments_lexer": "ipython3",
333 | "version": "3.8.8"
334 | }
335 | },
336 | "nbformat": 4,
337 | "nbformat_minor": 5
338 | }
339 |
--------------------------------------------------------------------------------
/01 Connected-component labeling/connected_component_labeling.py:
--------------------------------------------------------------------------------
1 | """
2 | Do the following image processing with Python programming.
3 |
4 | 1. Conduct a thresholding with a threshold=200
5 | 2. Delete all the regions which are less than 10,000
6 | 3. Count the number of remaining regions
7 | """
8 |
9 | from PIL import Image
10 | import numpy as np
11 | import matplotlib.pyplot as plt
12 |
13 | # 1. Conduct a thresholding with a threshold=200
14 |
15 | # (1) read image
16 | img = Image.open('Rose-BMP.bmp').convert('L')
17 | gray_img = np.array(img)
18 |
19 | plt.figure(1)
20 | plt.imshow(gray_img, cmap='gray')
21 | plt.show()
22 |
23 | # (2) thresholded binary image
24 | bin_img = gray_img.copy()
25 |
26 | threshold = 200
27 | bin_img[bin_img=threshold] = 1
29 |
30 | plt.figure(2)
31 | plt.imshow(bin_img, cmap='gray')
32 | plt.show()
33 |
34 | # 2. Delete all the regions which are less than 10,000
35 |
36 | connectivity_4 = np.array([[0,1,0],
37 | [1,0,0],
38 | [0,0,0]])
39 |
40 | connectivity_8 = np.array([[1,1,1],
41 | [1,0,0],
42 | [0,0,0]])
43 |
44 | def find_labels(labels, r, c, neighbors):
45 |
46 | tmp_labels = labels[r-1:r+2, c-1:c+2]*neighbors
47 |
48 | return np.sort(tmp_labels[np.nonzero(tmp_labels)])
49 |
50 | def connected_component_labeling(bin_img, connectivity=connectivity_8):
51 |
52 | equivalent = []
53 | labels = np.zeros_like(bin_img, dtype='int64')
54 | next_label = 1
55 |
56 | # 1st pass
57 | for r, row in enumerate(bin_img):
58 | for c, pixel in enumerate(row):
59 |
60 | if pixel!=0:
61 | neighbors = bin_img[r-1:r+2, c-1:c+2]*connectivity
62 | num_neighbors = np.count_nonzero(neighbors)
63 |
64 | if num_neighbors==0:
65 | labels[r,c] = next_label
66 | equivalent.append([next_label,next_label])
67 | next_label += 1
68 | else:
69 | L = find_labels(labels, r, c, neighbors)
70 | labels[r,c] = np.min(L)
71 |
72 | uni_L = np.unique(L)
73 | if len(uni_L)>1:
74 | for i, e in enumerate(equivalent):
75 | if uni_L[0] in e:
76 | equivalent[i].extend(uni_L[1:])
77 | equivalent[i] = list(sorted(set(equivalent[i])))
78 | # 2nd pass
79 | for e in equivalent:
80 | for f in reversed(e):
81 | labels[labels==f] = e[0]
82 |
83 | return labels
84 |
85 | def threshold_labels(labels, threshold=10000):
86 |
87 | unique_elements, counts_elements = np.unique(labels, return_counts=True)
88 | thr_elements = unique_elements[counts_elements>threshold]
89 |
90 | thr_labels = np.zeros_like(labels)
91 |
92 | cnt = 0
93 | for e in thr_elements:
94 | if e != 0:
95 | cnt += 1
96 | thr_labels[labels==e] = cnt
97 |
98 | return thr_labels
99 |
100 | labels_4 = connected_component_labeling(bin_img, connectivity_4)
101 | thr_labels_4 = threshold_labels(labels_4)
102 |
103 | plt.figure(3)
104 | plt.title('4-connectivity')
105 | plt.imshow(thr_labels_4)
106 | plt.show()
107 |
108 | labels_8 = connected_component_labeling(bin_img, connectivity_8)
109 | thr_labels_8 = threshold_labels(labels_8)
110 |
111 | plt.figure(4)
112 | plt.title('8-connectivity')
113 | plt.imshow(thr_labels_8)
114 | plt.show()
115 |
116 | # 3. Count the number of remaining regions
117 |
118 | _, counts_elements_4 = np.unique(thr_labels_4, return_counts=True)
119 |
120 | print('\n')
121 | print('4-connectivity')
122 | for l, c in enumerate(counts_elements_4):
123 | print('label :', l)
124 | print('number of pixel :', c)
125 |
126 | _, counts_elements_8 = np.unique(thr_labels_8, return_counts=True)
127 |
128 | print('\n')
129 | print('8-connectivity')
130 | for l, c in enumerate(counts_elements_8):
131 | print('label :', l)
132 | print('number of pixel :', c)
133 |
--------------------------------------------------------------------------------
/01 Connected-component labeling/doc/4-connectivity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/01 Connected-component labeling/doc/4-connectivity.png
--------------------------------------------------------------------------------
/01 Connected-component labeling/doc/8-connectivity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/01 Connected-component labeling/doc/8-connectivity.png
--------------------------------------------------------------------------------
/01 Connected-component labeling/doc/binary_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/01 Connected-component labeling/doc/binary_image.png
--------------------------------------------------------------------------------
/01 Connected-component labeling/doc/origin_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/01 Connected-component labeling/doc/origin_image.png
--------------------------------------------------------------------------------
/02 Distance transform/README.md:
--------------------------------------------------------------------------------
1 | # Distance transform
2 |
3 | Detail : https://jstar0525.tistory.com/3
4 |
5 | ## Input image
6 |
7 |
8 | ## Distance transform
9 | ### using Euclidean distance(De)
10 |
11 |
12 | ## Distance transform
13 | ### using City block distance(D4)
14 |
15 |
16 | ## Distance transform
17 | ### using Chessboard distance(D8)
18 |
19 |
--------------------------------------------------------------------------------
/02 Distance transform/distance_transform.py:
--------------------------------------------------------------------------------
1 | """
2 | Conduct a distance transform
3 | for the following obstacle image.
4 | """
5 |
6 | from PIL import Image
7 | import numpy as np
8 | import matplotlib.pyplot as plt
9 |
10 | # 1. read image
11 |
12 | img = Image.open('paperPhoto2021031918372826.bmp').convert('L')
13 | gray_img = gray_img = np.array(img)
14 |
15 | plt.figure(1)
16 | plt.imshow(gray_img, cmap='gray')
17 | plt.show()
18 |
19 | # 2. make distance metrics
20 |
21 | def De(a,b):
22 |
23 | r_square = (a[0]-b[0])**2
24 | c_square = (a[1]-b[1])**2
25 |
26 | return (r_square+c_square)**0.5
27 |
28 | def D4(a,b):
29 |
30 | r_abs = abs(a[0]-b[0])
31 | c_abs = abs(a[1]-b[1])
32 |
33 | return r_abs+c_abs
34 |
35 | def D8(a,b):
36 |
37 | r_abs = abs(a[0]-b[0])
38 | c_abs = abs(a[1]-b[1])
39 |
40 | return max(r_abs,c_abs)
41 |
42 | def D(D_type=D4):
43 |
44 | result_D = np.zeros((3,3))
45 |
46 | for i in range(3):
47 | for j in range(3):
48 | result_D[i,j] = D_type([i,j],[1,1])
49 |
50 | return result_D
51 |
52 |
53 | # 3. Conduct a distance transform for the following obstacle image
54 |
55 | def distance_transform(gray_img, D_type=D4):
56 |
57 | al = np.array([[1,1,0],
58 | [1,0,0],
59 | [1,0,0]])
60 |
61 | br = np.array([[0,0,1],
62 | [0,0,1],
63 | [0,1,1]])
64 |
65 | # 1
66 | row, col = gray_img.shape
67 | N_max = row+col
68 | F = np.zeros_like(gray_img, dtype='float64')
69 | F[gray_img==0] = N_max
70 |
71 | while(True):
72 | # 2
73 | for r in range(1,row-1):
74 | for c in range(1,col-1):
75 | df = ( D(D_type)+F[r-1:r+2,c-1:c+2] )*al
76 | df[1,1] = F[r,c]
77 | F[r,c] = np.min(df[np.nonzero(df)])
78 | # 3
79 | for r in reversed(range(1,row-1)):
80 | for c in reversed(range(1,col-1)):
81 | df = ( D(D_type)+F[r-1:r+2,c-1:c+2] )*br
82 | df[1,1] = F[r,c]
83 | F[r,c] = np.min(df[np.nonzero(df)])
84 | # 4
85 | if np.any(F!=N_max):
86 | break
87 |
88 | return F
89 |
90 | F_De = distance_transform(gray_img, D_type=De)
91 |
92 | plt.figure(2)
93 | plt.title('F_De')
94 | plt.imshow(F_De)
95 | plt.show()
96 |
97 | F_D4 = distance_transform(gray_img, D_type=D4)
98 |
99 | plt.figure(3)
100 | plt.title('F_D4')
101 | plt.imshow(F_D4)
102 | plt.show()
103 |
104 | F_D8 = distance_transform(gray_img, D_type=D8)
105 |
106 | plt.figure(4)
107 | plt.title('F_D8')
108 | plt.imshow(F_D8)
109 | plt.show()
110 |
111 |
112 |
--------------------------------------------------------------------------------
/02 Distance transform/doc/D4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/02 Distance transform/doc/D4.png
--------------------------------------------------------------------------------
/02 Distance transform/doc/D8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/02 Distance transform/doc/D8.png
--------------------------------------------------------------------------------
/02 Distance transform/doc/De.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/02 Distance transform/doc/De.png
--------------------------------------------------------------------------------
/02 Distance transform/doc/origin_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/02 Distance transform/doc/origin_image.png
--------------------------------------------------------------------------------
/02 Distance transform/paperPhoto2021031918372826.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/02 Distance transform/paperPhoto2021031918372826.bmp
--------------------------------------------------------------------------------
/03 Contrast stretching/README.md:
--------------------------------------------------------------------------------
1 | # Contrast stretching
2 |
3 | Detail : https://jstar0525.tistory.com/6
4 |
5 | ## Input image
6 |
7 |
8 |
9 | ## Contrast stretching
10 |
11 |
12 |
13 | ## Input image
14 |
15 |
16 |
17 | ## Contrast stretching
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/03 Contrast stretching/contrast_stretching.py:
--------------------------------------------------------------------------------
1 | """
2 | Perform simulations about the attached two images as following.
3 |
4 | Enhance the images using Contrast stretching
5 | """
6 |
7 |
8 | from PIL import Image
9 | import numpy as np
10 | import matplotlib.pyplot as plt
11 |
12 |
13 | def contrast_stretching(img, newMin=0, newMax=75):
14 |
15 | ch_img = img.copy()
16 |
17 | ch_img[ch_img<=newMin] = newMin
18 | ch_img[ch_img>=newMax] = newMax
19 |
20 | result = (ch_img - newMin) / (newMax - newMin) * 255
21 |
22 | return result
23 |
24 | def show(img, max_ylim=12500):
25 |
26 | # show image
27 | plt.imshow(img, cmap='gray')
28 | plt.show()
29 |
30 | # show histogram
31 | if max_ylim != 'none':
32 | axes = plt.axes()
33 | axes.set_ylim([0, max_ylim])
34 | plt.hist(img.ravel(), bins=256, range=[0,256])
35 | plt.show()
36 |
37 | # image 1
38 | img_1 = Image.open('paperPhoto20210402174743810.bmp').convert('L')
39 |
40 | npimg_1 = np.array(img_1)
41 | show(npimg_1, max_ylim=12500)
42 |
43 | stimg_1 = contrast_stretching(npimg_1, newMin=0, newMax=75)
44 | show(stimg_1, max_ylim=12500)
45 |
46 |
47 | # image 2
48 | img_2 = Image.open('paperPhoto20210402174743817.bmp').convert('L')
49 |
50 | npimg_2 = np.array(img_2)
51 | show(npimg_2, max_ylim=4500)
52 |
53 | stimg_2 = contrast_stretching(npimg_2, newMin=100, newMax=255)
54 | show(stimg_2, max_ylim=4500)
55 |
56 |
--------------------------------------------------------------------------------
/03 Contrast stretching/doc/origin_hist1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/03 Contrast stretching/doc/origin_hist1.png
--------------------------------------------------------------------------------
/03 Contrast stretching/doc/origin_hist2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/03 Contrast stretching/doc/origin_hist2.png
--------------------------------------------------------------------------------
/03 Contrast stretching/doc/origin_img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/03 Contrast stretching/doc/origin_img1.png
--------------------------------------------------------------------------------
/03 Contrast stretching/doc/origin_img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/03 Contrast stretching/doc/origin_img2.png
--------------------------------------------------------------------------------
/03 Contrast stretching/doc/st_hist1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/03 Contrast stretching/doc/st_hist1.png
--------------------------------------------------------------------------------
/03 Contrast stretching/doc/st_hist2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/03 Contrast stretching/doc/st_hist2.png
--------------------------------------------------------------------------------
/03 Contrast stretching/doc/st_img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/03 Contrast stretching/doc/st_img1.png
--------------------------------------------------------------------------------
/03 Contrast stretching/doc/st_img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/03 Contrast stretching/doc/st_img2.png
--------------------------------------------------------------------------------
/03 Contrast stretching/paperPhoto20210402174743810.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/03 Contrast stretching/paperPhoto20210402174743810.bmp
--------------------------------------------------------------------------------
/03 Contrast stretching/paperPhoto20210402174743817.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/03 Contrast stretching/paperPhoto20210402174743817.bmp
--------------------------------------------------------------------------------
/04 Histogram equalization/README.md:
--------------------------------------------------------------------------------
1 | # Histogram equalization
2 |
3 | Detail : https://jstar0525.tistory.com/7
4 |
5 | ## Input image
6 |
7 |
8 |
9 | ### monotonic pixel brightness transformation T
10 |
11 |
12 | ### Histogram equalization
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ## Input image
21 |
22 |
23 |
24 | ### monotonic pixel brightness transformation T
25 |
26 |
27 | ### Histogram equalization
28 |
29 |
--------------------------------------------------------------------------------
/04 Histogram equalization/doc/T1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/doc/T1.png
--------------------------------------------------------------------------------
/04 Histogram equalization/doc/T2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/doc/T2.png
--------------------------------------------------------------------------------
/04 Histogram equalization/doc/eq_hist1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/doc/eq_hist1.png
--------------------------------------------------------------------------------
/04 Histogram equalization/doc/eq_hist2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/doc/eq_hist2.png
--------------------------------------------------------------------------------
/04 Histogram equalization/doc/eq_img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/doc/eq_img1.png
--------------------------------------------------------------------------------
/04 Histogram equalization/doc/eq_img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/doc/eq_img2.png
--------------------------------------------------------------------------------
/04 Histogram equalization/doc/origin_hist1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/doc/origin_hist1.png
--------------------------------------------------------------------------------
/04 Histogram equalization/doc/origin_hist2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/doc/origin_hist2.png
--------------------------------------------------------------------------------
/04 Histogram equalization/doc/origin_img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/doc/origin_img1.png
--------------------------------------------------------------------------------
/04 Histogram equalization/doc/origin_img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/doc/origin_img2.png
--------------------------------------------------------------------------------
/04 Histogram equalization/histogram_equalization.py:
--------------------------------------------------------------------------------
1 | """
2 | Perform simulations about the attached two images as following.
3 |
4 | Enhance the images using Histogram equalization method
5 | """
6 |
7 | from PIL import Image
8 | import numpy as np
9 | import matplotlib.pyplot as plt
10 |
11 | def histogram_equalization(img):
12 |
13 | # 1
14 | (N, M) = img.shape
15 |
16 | G = 256 # gray levels
17 | H = np.zeros(G) # initialize an array Histogram
18 |
19 | # 2
20 | for g in img.ravel():
21 | H[g] += 1
22 |
23 | g_min = np.min(np.nonzero(H))
24 |
25 | # 3
26 | H_c = np.zeros_like(H) # cumulative image histogram
27 | H_c[0] = H[0]
28 | for g in range(1,G):
29 | H_c[g] = H_c[g-1] + H[g]
30 |
31 | H_min = H_c[g_min]
32 |
33 | # 4
34 | T = np.round( (H_c - H_min) / (M*N - H_min) * (G-1) )
35 |
36 | # 5
37 | result = np.zeros_like(img)
38 | for n in range(N):
39 | for m in range(M):
40 | result[n,m] = T[img[n,m]]
41 |
42 | return result, T
43 |
44 | def show_Hc(img, max_ylim=12500):
45 |
46 | # show image
47 | plt.figure()
48 | plt.imshow(img, cmap='gray')
49 | plt.show()
50 |
51 | G = 256 # gray levels
52 | H = np.zeros(G)
53 |
54 | for g in img.ravel():
55 | H[g] += 1
56 |
57 | H_c = np.zeros_like(H) # cumulative image histogram
58 | H_c[0] = H[0]
59 | for g in range(1,G):
60 | H_c[g] = H_c[g-1] + H[g]
61 |
62 | # show histogram
63 | fig, ax1 = plt.subplots()
64 | if max_ylim != 'none':
65 | ax1.set_ylim([0, max_ylim])
66 | ax1.set_ylabel('histogram', color='C0')
67 | ax1.hist(img.ravel(), bins=256, range=[0,256], color='C0')
68 | ax1.tick_params(axis='y', labelcolor='C0')
69 |
70 | ax2 = ax1.twinx()
71 | ax2.set_ylabel('cumulative histogram', color='C1')
72 | ax2.plot(H_c, color='C1')
73 | ax2.tick_params(axis='y', labelcolor='C1')
74 | plt.show()
75 |
76 |
77 | # image 1
78 | img_1 = Image.open('paperPhoto20210402174743810.bmp').convert('L')
79 |
80 | npimg_1 = np.array(img_1)
81 | show_Hc(npimg_1, max_ylim=12500)
82 |
83 | eqimg_1, T1 = histogram_equalization(npimg_1)
84 | plt.figure()
85 | plt.title('monotonic pixel brightness transformation T')
86 | plt.plot(T1)
87 | plt.show()
88 | show_Hc(eqimg_1, max_ylim=12500)
89 |
90 |
91 | # image 2
92 | img_2 = Image.open('paperPhoto20210402174743817.bmp').convert('L')
93 |
94 | npimg_2 = np.array(img_2)
95 | show_Hc(npimg_2, max_ylim=3500)
96 |
97 | eqimg_2, T2 = histogram_equalization(npimg_2)
98 | plt.figure()
99 | plt.title('monotonic pixel brightness transformation T')
100 | plt.plot(T2)
101 | plt.show()
102 | show_Hc(eqimg_2, max_ylim=3500)
103 |
--------------------------------------------------------------------------------
/04 Histogram equalization/paperPhoto20210402174743810.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/paperPhoto20210402174743810.bmp
--------------------------------------------------------------------------------
/04 Histogram equalization/paperPhoto20210402174743817.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/04 Histogram equalization/paperPhoto20210402174743817.bmp
--------------------------------------------------------------------------------
/05 Median filtering/README.md:
--------------------------------------------------------------------------------
1 | # Median filtering
2 |
3 | Detail : https://jstar0525.tistory.com/8
4 |
5 | ## Input image
6 |
7 |
8 |
9 | ### Median filtering 3x3
10 |
11 |
12 |
13 | ### Median filtering 5x5
14 |
15 |
16 |
17 | ## Input image
18 |
19 |
20 |
21 | ### Median filtering 3x3
22 |
23 |
24 |
25 | ### Median filtering 5x5
26 |
27 |
28 |
--------------------------------------------------------------------------------
/05 Median filtering/doc/3f_hist1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/3f_hist1.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/3f_hist2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/3f_hist2.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/3f_img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/3f_img1.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/3f_img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/3f_img2.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/5f_hist1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/5f_hist1.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/5f_hist2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/5f_hist2.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/5f_img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/5f_img1.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/5f_img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/5f_img2.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/origin_hist1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/origin_hist1.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/origin_hist2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/origin_hist2.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/origin_img1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/origin_img1.png
--------------------------------------------------------------------------------
/05 Median filtering/doc/origin_img2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/doc/origin_img2.png
--------------------------------------------------------------------------------
/05 Median filtering/median_filtering.py:
--------------------------------------------------------------------------------
1 | """
2 | Perform simulations about the attached two images as following.
3 |
4 | Apply median filtering about two images.
5 | Then, compare the results before and after the filtering.
6 | """
7 |
8 | from PIL import Image
9 | import numpy as np
10 | import matplotlib.pyplot as plt
11 |
12 | def show(img, max_ylim=12500):
13 |
14 | # show image
15 | plt.imshow(img, cmap='gray')
16 | plt.show()
17 |
18 | # show histogram
19 | if max_ylim != 'none':
20 | axes = plt.axes()
21 | axes.set_ylim([0, max_ylim])
22 | plt.hist(img.ravel(), bins=256, range=[0,256])
23 | plt.show()
24 |
25 | def median_filter(img, filter_size=(3, 3), stride=1):
26 |
27 | img_shape = np.shape(img)
28 |
29 | result_shape = tuple( np.int64(
30 | (np.array(img_shape)-np.array(filter_size))/stride+1
31 | ) )
32 |
33 | result = np.zeros(result_shape)
34 |
35 | for h in range(0, result_shape[0], stride):
36 | for w in range(0, result_shape[1], stride):
37 | tmp = img[h:h+filter_size[0],w:w+filter_size[1]]
38 | tmp = np.sort(tmp.ravel())
39 | result[h,w] = tmp[int(filter_size[0]*filter_size[1]/2)]
40 |
41 | return result
42 |
43 | # image 1
44 | img_1 = Image.open('paperPhoto20210402174743810.bmp').convert('L')
45 | npimg_1 = np.array(img_1)
46 | show(npimg_1, max_ylim=12500)
47 |
48 | med_img_1 = median_filter(npimg_1)
49 | show(med_img_1, max_ylim=12500)
50 |
51 | med_img_1 = median_filter(npimg_1, (5,5))
52 | show(med_img_1, max_ylim=12500)
53 |
54 | # image 2
55 | img_2 = Image.open('paperPhoto20210402174743817.bmp').convert('L')
56 | npimg_2 = np.array(img_2)
57 | show(npimg_2, max_ylim=4500)
58 |
59 | med_img_2 = median_filter(npimg_2)
60 | show(med_img_2, max_ylim=4500)
61 |
62 | med_img_2 = median_filter(npimg_2, (5,5))
63 | show(med_img_2, max_ylim=4500)
64 |
--------------------------------------------------------------------------------
/05 Median filtering/paperPhoto20210402174743810.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/paperPhoto20210402174743810.bmp
--------------------------------------------------------------------------------
/05 Median filtering/paperPhoto20210402174743817.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/05 Median filtering/paperPhoto20210402174743817.bmp
--------------------------------------------------------------------------------
/06 Edge Detection/README.md:
--------------------------------------------------------------------------------
1 | # Edge detection
2 |
3 | Detail : https://jstar0525.tistory.com/53
4 |
5 | ## Input image
6 |
7 |
8 | ### Roberts operator
9 |
10 |
11 |
12 |
13 |
14 | ### Sobel operator
15 |
16 |
17 |
18 |
19 |
20 | ### Prewitt operator
21 |
22 |
23 |
24 |
25 |
26 | ### LoG (The Laplacian of Gaussian)
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/06 Edge Detection/doc/log_3_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/log_3_1.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/log_3_1_thr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/log_3_1_thr.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/log_3_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/log_3_2.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/log_3_2_thr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/log_3_2_thr.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/log_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/log_5.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/log_5_thr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/log_5_thr.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/log_9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/log_9.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/log_9_thr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/log_9_thr.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/origin_img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/origin_img.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/prewitt_sum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/prewitt_sum.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/prewitt_thr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/prewitt_thr.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/prewitt_x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/prewitt_x.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/prewitt_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/prewitt_y.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/roberts_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/roberts_1.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/roberts_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/roberts_2.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/roberts_sum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/roberts_sum.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/roberts_thr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/roberts_thr.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/sobel_sum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/sobel_sum.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/sobel_thr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/sobel_thr.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/sobel_x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/sobel_x.png
--------------------------------------------------------------------------------
/06 Edge Detection/doc/sobel_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/doc/sobel_y.png
--------------------------------------------------------------------------------
/06 Edge Detection/edge_detection.py:
--------------------------------------------------------------------------------
1 | """
2 | Following is black and white Lena image.
3 |
4 | 1. Compare the Edge detection performances with Sobel, Robert, Prewitt, LOG operators:
5 | 2. Describe their characteristic differences based on your simulation results
6 | """
7 |
8 | from PIL import Image
9 | import numpy as np
10 | import matplotlib.pyplot as plt
11 |
12 | #%% read image and operator
13 |
14 | img = Image.open('lena.png').convert('L')
15 | img = np.array(img)
16 |
17 | roberts_1 = np.array([[ 1, 0],
18 | [ 0,-1]])
19 |
20 | roberts_2 = np.array([[ 0, 1],
21 | [-1, 0]])
22 |
23 | sobel_x = np.array([[-1, 0, 1],
24 | [-2, 0, 2],
25 | [-1, 0, 1]])
26 |
27 | sobel_y = np.array([[ 1, 2, 1],
28 | [ 0, 0, 0],
29 | [-1,-2,-1]])
30 |
31 | prewitt_x = np.array([[-1, 0, 1],
32 | [-1, 0, 1],
33 | [-1, 0, 1]])
34 |
35 | prewitt_y = np.array([[ 1, 1, 1],
36 | [ 0, 0, 0],
37 | [-1,-1,-1]])
38 |
39 | LoG_3_1 = np.array([[ 0,-1, 0],
40 | [-1, 4,-1],
41 | [ 0,-1, 0]])
42 |
43 | LoG_3_2 = np.array([[-1,-1,-1],
44 | [-1, 8,-1],
45 | [-1,-1,-1]])
46 |
47 | LoG_5 = np.array([[ 0, 0,-1, 0, 0],
48 | [ 0,-1,-2,-1, 0],
49 | [-1,-2,16,-2,-1],
50 | [ 0,-1,-2,-1, 0],
51 | [ 0, 0,-1, 0, 0]])
52 |
53 | LoG_9 = np.array([[ 0, 1, 1, 2, 2, 2, 1, 1, 0],
54 | [ 1, 2, 4, 5, 5, 5, 4, 2, 1],
55 | [ 1, 4, 5, 3, 0, 3, 5, 4, 1],
56 | [ 2, 5, 3,-12,-24,-12, 3, 5, 2],
57 | [ 2, 5, 0,-24,-40,-24, 0, 5, 2],
58 | [ 2, 5, 3,-12,-24,-12, 3, 5, 2],
59 | [ 1, 4, 5, 3, 0, 3, 5, 4, 1],
60 | [ 1, 2, 4, 5, 5, 5, 4, 2, 1],
61 | [ 0, 1, 1, 2, 2, 2, 1, 1, 0]])
62 |
63 | #%% function
64 |
65 | def show(img, result1, result2, result, thr_result):
66 |
67 | plt.imshow(img, cmap='gray')
68 | plt.show()
69 |
70 | plt.imshow(result1, cmap='gray')
71 | plt.show()
72 |
73 | plt.imshow(result2, cmap='gray')
74 | plt.show()
75 |
76 | plt.imshow(result, cmap='gray')
77 | plt.show()
78 |
79 | plt.imshow(thr_result, cmap='gray')
80 | plt.show()
81 |
82 | def edge_detection(img, mask1, mask2, threshold, show_img=True):
83 |
84 | img_shape = img.shape
85 |
86 | try:
87 | if mask1.shape != mask2.shape:
88 | raise Exception('마스크의 크기가 서로 다릅니다.')
89 | filter_size = mask1.shape
90 | except Exception as e:
91 | print('예외가 발생했습니다.', e)
92 |
93 | result_shape = tuple(np.array(img_shape)-np.array(filter_size)+1)
94 |
95 | result1 = np.zeros(result_shape)
96 | result2 = np.zeros(result_shape)
97 |
98 | for h in range(0, result_shape[0]):
99 | for w in range(0, result_shape[1]):
100 | tmp = img[h:h+filter_size[0],w:w+filter_size[1]]
101 | result1[h,w] = np.abs(np.sum(tmp*mask1))
102 | result2[h,w] = np.abs(np.sum(tmp*mask2))
103 |
104 | result = result1 + result2
105 |
106 | thr_result = np.zeros(result_shape)
107 | thr_result[result>threshold] = 1
108 |
109 | if show_img:
110 | show(img, result1, result2, result, thr_result)
111 |
112 | return result1, result2, result, thr_result
113 |
114 | #%%
115 |
116 | edge_detection(img, roberts_1, roberts_2, threshold=50)
117 |
118 | edge_detection(img, sobel_x, sobel_y, threshold=140)
119 |
120 | edge_detection(img, prewitt_x, prewitt_y, threshold=100)
121 |
122 | edge_detection(img, LoG_3_1, np.zeros_like(LoG_3_1), threshold=70)
123 | edge_detection(img, LoG_3_2, np.zeros_like(LoG_3_2), threshold=150)
124 | edge_detection(img, LoG_5, np.zeros_like(LoG_5), threshold=300)
125 | edge_detection(img, LoG_9, np.zeros_like(LoG_9), threshold=2000)
126 |
127 |
128 |
--------------------------------------------------------------------------------
/06 Edge Detection/lena.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/06 Edge Detection/lena.png
--------------------------------------------------------------------------------
/07 Frequency domain filtering/README.md:
--------------------------------------------------------------------------------
1 | # Frequency domain filtering
2 |
3 | Detail : https://jstar0525.tistory.com/59
4 |
5 | ## Input image
6 |
7 |
8 | ## FFT
9 |
10 |
11 | ## FFT shift
12 |
13 |
14 | ## filtering
15 | ### low-pass filter
16 |
17 |
18 |
19 | ### high-pass filter
20 |
21 |
22 | ## inverse FFT
23 | ### low-pass filter
24 |
25 |
26 |
27 | ### high-pass filter
28 |
--------------------------------------------------------------------------------
/07 Frequency domain filtering/Rose-BMP.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/07 Frequency domain filtering/Rose-BMP.bmp
--------------------------------------------------------------------------------
/07 Frequency domain filtering/doc/fft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/07 Frequency domain filtering/doc/fft.png
--------------------------------------------------------------------------------
/07 Frequency domain filtering/doc/fft_shift.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/07 Frequency domain filtering/doc/fft_shift.png
--------------------------------------------------------------------------------
/07 Frequency domain filtering/doc/high_pass_filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/07 Frequency domain filtering/doc/high_pass_filter.png
--------------------------------------------------------------------------------
/07 Frequency domain filtering/doc/inverse_fft_high.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/07 Frequency domain filtering/doc/inverse_fft_high.png
--------------------------------------------------------------------------------
/07 Frequency domain filtering/doc/inverse_fft_low.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/07 Frequency domain filtering/doc/inverse_fft_low.png
--------------------------------------------------------------------------------
/07 Frequency domain filtering/doc/inverse_fft_low_r20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/07 Frequency domain filtering/doc/inverse_fft_low_r20.png
--------------------------------------------------------------------------------
/07 Frequency domain filtering/doc/low_pass_filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/07 Frequency domain filtering/doc/low_pass_filter.png
--------------------------------------------------------------------------------
/07 Frequency domain filtering/doc/low_pass_filter_r20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/07 Frequency domain filtering/doc/low_pass_filter_r20.png
--------------------------------------------------------------------------------
/07 Frequency domain filtering/doc/origin_img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/07 Frequency domain filtering/doc/origin_img.png
--------------------------------------------------------------------------------
/07 Frequency domain filtering/frequency_domain_filtering.py:
--------------------------------------------------------------------------------
1 | """
2 | Perform following filtering using the radius of 50 pixels.
3 |
4 | a) Low Pass Filtering
5 | : Transform the image into Frequency Domain
6 | : Manipulate the frequency components
7 | : Transform the manipulated freq. Components to the spatial domain.
8 | b) High Pass Filtering.
9 | c) Compare the above two processing results.
10 | """
11 |
12 | from PIL import Image
13 | import numpy as np
14 | import matplotlib.pyplot as plt
15 |
16 | def cal_D(c_row, c_col, r, c):
17 | s = (c_row-r)**2 + (c_col-c)**2
18 | return s**(1/2)
19 |
20 | def filter_radius(fshift, rad, low=True):
21 | rows, cols = fshift.shape
22 | c_row, c_col = int(rows/2), int(cols/2) # center
23 |
24 | filter_fshift = fshift.copy()
25 |
26 | for r in range(rows):
27 | for c in range(cols):
28 | if low: # low-pass filter
29 | if cal_D(c_row, c_col, r, c) > rad:
30 | filter_fshift[r,c] = 0
31 | else: # high-pass filter
32 | if cal_D(c_row, c_col, r, c) < rad:
33 | filter_fshift[r,c] = 0
34 |
35 | return filter_fshift
36 |
37 | # read image
38 | img = Image.open('Rose-BMP.bmp').convert('L')
39 | gray_img = np.array(img)
40 |
41 | plt.imshow(gray_img, cmap='gray')
42 | plt.show()
43 |
44 | # fft
45 | f = np.fft.fft2(gray_img)
46 | magnitude_f = np.log(np.abs(f)+1)
47 |
48 | plt.imshow(magnitude_f, cmap='gray')
49 | plt.show()
50 |
51 | # fftshift
52 | fshift = np.fft.fftshift(f)
53 | magnitude_fshift = np.log(np.abs(fshift)+1)
54 |
55 | plt.imshow(magnitude_fshift, cmap='gray')
56 | plt.show()
57 |
58 | # low-pass filter
59 | low_fshift = filter_radius(fshift, rad=50, low=True)
60 | low_pass_magnitude = np.log(np.abs(low_fshift)+1)
61 |
62 | plt.imshow(low_pass_magnitude, cmap='gray')
63 | plt.show()
64 |
65 | # low-pass filter inverse fft
66 | low_ishift = np.fft.ifftshift(low_fshift)
67 | low_img = np.fft.ifft2(low_ishift)
68 | low_img = np.abs(low_img)
69 |
70 | plt.imshow(low_img, cmap='gray')
71 | plt.show()
72 |
73 | # high-pass filter
74 | high_fshift = filter_radius(fshift, rad=50, low=False)
75 | high_pass_magnitude = np.log(np.abs(high_fshift)+1)
76 |
77 | plt.imshow(high_pass_magnitude, cmap='gray')
78 | plt.show()
79 |
80 | # high-pass filter inverse fft
81 | high_ishift = np.fft.ifftshift(high_fshift)
82 | high_img = np.fft.ifft2(high_ishift)
83 | high_img = np.abs(high_img)
84 |
85 | plt.imshow(high_img, cmap='gray')
86 | plt.show()
--------------------------------------------------------------------------------
/08 Convolution theorem/README.md:
--------------------------------------------------------------------------------
1 | # Convolution theorem
2 |
3 | Detail : https://jstar0525.tistory.com/65
4 |
5 |
6 | ## Input image
7 |
8 |
9 | ## FFT
10 |
11 |
12 |
13 | ## Element-wise product
14 |
15 |
16 | ## inverse FFT
17 |
18 |
19 | ## Convolution
20 |
--------------------------------------------------------------------------------
/08 Convolution theorem/Rose-BMP.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/08 Convolution theorem/Rose-BMP.bmp
--------------------------------------------------------------------------------
/08 Convolution theorem/convolution_theorem.py:
--------------------------------------------------------------------------------
1 | """
2 | Comparison between Spatial and Frequency Domain Filtering
3 |
4 | Conduct the comparison between Spatial and Frequency Domain Filtering about the attached Rose image i
5 | via experiments of following procedure.
6 | h(x,y) below is the Sobel mask for horizontal edge detection.
7 |
8 | 1) Conduct the Fourier Transform about the image i. Let its result be I(u,v).
9 | 2) Conduct Fourier transform about the Sobel mask h(x,y). Let the result be H(u,v).
10 | 3) Conduct the element-wise multiplication between I(u,v) and H(u,v). Let its result be I’(u,v).
11 | I’(u,v)=I(u,v)H(u,v)
12 | Then, show the I’(u,v) in an image.
13 | 4) Conduct the inverse Fourier Transform of I’(u,v). Let its result be i’(x,y).
14 | Then, show the image i’(x,y).
15 | 5) Conduct a mask processing of h(x,y) on the Spatial domain about the original image i.
16 | Let the resultant image be i’’(x,y).
17 | And, make a comparison between the above two images, i’(x,y) and i’’(x,y).
18 |
19 | h(x,y) =
20 | 1 2 1
21 | 0 0 0
22 | -1 -2 -1
23 | """
24 |
25 | from PIL import Image
26 | import numpy as np
27 | import matplotlib.pyplot as plt
28 |
29 | # read image
30 | img = Image.open('Rose-BMP.bmp').convert('L')
31 | i = np.array(img)
32 |
33 | # make a odd shape image
34 | if i.shape[0]%2 == 0:
35 | i = i[:i.shape[0]-1,:]
36 | if i.shape[1]%2 == 0:
37 | i = i[:,:i.shape[1]-1]
38 |
39 | plt.imshow(i, cmap='gray')
40 | plt.show()
41 |
42 | #%% fft
43 |
44 | I = np.fft.fft2(i)
45 | I_s = np.fft.fftshift(I)
46 |
47 | plt.imshow(np.log(np.abs(I_s)+1), cmap='gray')
48 | plt.show()
49 |
50 | #%% sobel
51 |
52 | h = np.array([[ 1, 2, 1],
53 | [ 0, 0, 0],
54 | [-1,-2,-1]])
55 |
56 | def fft_filter(h, filter_size=1023, crop_size=1023):
57 |
58 | if crop_size >= filter_size:
59 | filter_size = crop_size
60 |
61 | p = int((filter_size-h.shape[0])/2)
62 | h_p = np.pad(h, ((p,p),(p,p)), 'constant', constant_values=0)
63 |
64 | H = np.fft.fft2(h_p)
65 |
66 | if crop_size >= filter_size:
67 | return H
68 | else:
69 | start = int((filter_size-crop_size)/2)
70 | last = int(start+crop_size)
71 |
72 | return H[start:last,start:last]
73 |
74 | H = fft_filter(h, filter_size=1023, crop_size=1023)
75 | H_s = np.fft.fftshift(H)
76 |
77 | plt.imshow(np.log(np.abs(H_s)+1), cmap='gray')
78 | plt.show()
79 |
80 | #%% element-wise multiplication
81 |
82 | I_prime = I_s*np.log(np.abs(H_s)+1)
83 |
84 | plt.imshow(np.log(abs(I_prime)+1), cmap='gray')
85 | plt.show()
86 |
87 | #%% inverse FFT
88 |
89 | i_prime = np.fft.ifftshift(I_prime)
90 | i_prime = np.fft.ifft2(i_prime)
91 | i_prime[i_prime>255] = 255
92 |
93 | plt.imshow(np.abs(i_prime), cmap='gray')
94 | plt.show()
95 |
96 | #%% Spatail domain filtering
97 |
98 | def conv(img, i_filter, stride):
99 |
100 | result_shape = tuple( np.int64(
101 | (np.array(img.shape)-np.array(i_filter.shape))/stride+1
102 | ) )
103 |
104 | result = np.zeros(result_shape)
105 |
106 | for h in range(0, result_shape[0], stride):
107 | for w in range(0, result_shape[1], stride):
108 | tmp = img[h:h+i_filter.shape[0],w:w+i_filter.shape[1]]*i_filter
109 | result[h,w] = np.abs(np.sum(tmp))
110 |
111 | result[result>255] = 255
112 |
113 | return result
114 |
115 | result = conv(i, h, stride=1)
116 |
117 | plt.imshow(result, cmap='gray')
118 | plt.show()
119 |
120 |
--------------------------------------------------------------------------------
/08 Convolution theorem/doc/conv.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/08 Convolution theorem/doc/conv.png
--------------------------------------------------------------------------------
/08 Convolution theorem/doc/fft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/08 Convolution theorem/doc/fft.png
--------------------------------------------------------------------------------
/08 Convolution theorem/doc/ifft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/08 Convolution theorem/doc/ifft.png
--------------------------------------------------------------------------------
/08 Convolution theorem/doc/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/08 Convolution theorem/doc/img.png
--------------------------------------------------------------------------------
/08 Convolution theorem/doc/mul_fft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/08 Convolution theorem/doc/mul_fft.png
--------------------------------------------------------------------------------
/08 Convolution theorem/doc/sobel_fft.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/08 Convolution theorem/doc/sobel_fft.png
--------------------------------------------------------------------------------
/09 Hough transform/.pylint.d/untitled21.stats:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/.pylint.d/untitled21.stats
--------------------------------------------------------------------------------
/09 Hough transform/README.md:
--------------------------------------------------------------------------------
1 | # Hough transform
2 |
3 | Detail : https://jstar0525.tistory.com/66
4 |
5 |
6 | # Simple Example
7 | ## Input image
8 |
9 |
10 | ## Hough space
11 |
12 |
13 | ## Select lines
14 |
15 |
16 | # Example
17 |
18 | ## Input image
19 |
20 |
21 | ## Hough space
22 |
23 |
24 | ## Select lines
25 |
26 |
27 |
28 | ## filtering
29 |
--------------------------------------------------------------------------------
/09 Hough transform/doc/fig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/doc/fig.png
--------------------------------------------------------------------------------
/09 Hough transform/doc/fig_draw_lines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/doc/fig_draw_lines.png
--------------------------------------------------------------------------------
/09 Hough transform/doc/fig_filter_lines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/doc/fig_filter_lines.png
--------------------------------------------------------------------------------
/09 Hough transform/doc/fig_houghspace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/doc/fig_houghspace.png
--------------------------------------------------------------------------------
/09 Hough transform/doc/fig_select_lines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/doc/fig_select_lines.png
--------------------------------------------------------------------------------
/09 Hough transform/doc/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/doc/test.png
--------------------------------------------------------------------------------
/09 Hough transform/doc/test_houghspace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/doc/test_houghspace.png
--------------------------------------------------------------------------------
/09 Hough transform/doc/test_line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/doc/test_line.png
--------------------------------------------------------------------------------
/09 Hough transform/fig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/fig.png
--------------------------------------------------------------------------------
/09 Hough transform/hough_transform.py:
--------------------------------------------------------------------------------
1 | """
2 | 1. Following is an edge image.
3 | Draw the 10 most explicit straight lines using Hough Transform on the edge image.
4 |
5 | 2. Choose the straight lines which are within +- 10 degree
6 | from the horizontal axis among the above 10 lines.
7 | """
8 |
9 | from PIL import Image
10 | import numpy as np
11 | import matplotlib.pyplot as plt
12 |
13 | #%% read image
14 |
15 | img = Image.open('fig.png').convert('L')
16 | # img = Image.open('test.png').convert('L')
17 | bin_img = np.array(img)
18 | bin_img[bin_img>0] = 1
19 |
20 | plt.figure()
21 | plt.imshow(bin_img, cmap='gray')
22 | plt.title('Input Image')
23 | plt.show()
24 |
25 | #%% make hough space
26 |
27 | def make_hough_space(bin_img, theta_resolution = 0.1, rho_resolution = 1):
28 |
29 | global D, R, C
30 |
31 | R, C = bin_img.shape
32 |
33 | n_theta = int(180 / theta_resolution + 1)
34 | theta = np.linspace(-90, 90, n_theta)
35 | rad_theta = np.deg2rad(theta)
36 |
37 | D = int( np.sqrt(R**2 + C**2) )
38 | n_rho = int(D*2 / rho_resolution + 1)
39 | rho = np.linspace(-D, D, n_rho)
40 |
41 | hough_space = np.zeros((n_rho,n_theta))
42 | for r in range(R):
43 | for c in range(C):
44 | if bin_img[r,c]:
45 | for theta_idx, rad in enumerate(rad_theta):
46 | tmp = c*np.cos(rad) + r*np.sin(rad)
47 | rho_idx = np.argmin(abs(rho-tmp))
48 | hough_space[rho_idx, theta_idx] += 1
49 |
50 | return hough_space, rad_theta, rho
51 |
52 | hough_space, rad_theta, rho = make_hough_space(bin_img, theta_resolution = 0.1, rho_resolution = 1)
53 |
54 | plt.figure(figsize=(6,9))
55 | str_hough_space = hough_space*3 #3, 200
56 | str_hough_space[str_hough_space>255] = 255
57 | plt.imshow(str_hough_space, extent=[-90, 90, -D, D], cmap='jet', aspect=1 / 10)
58 | plt.title('Hough Space')
59 | plt.xlabel('Angles (degrees)')
60 | plt.ylabel('Distance (pixels)')
61 | plt.show()
62 |
63 | #%% take intersection points in hough space
64 |
65 | def select_lines(hough_space, rad_theta, rho, num=10, threshold=20):
66 |
67 | hough = hough_space.copy()
68 | idx = []
69 | while(len(idx) < num):
70 | rho_idx, theta_idx = np.unravel_index(hough.argmax(), hough.shape)
71 | if not idx:
72 | idx.append([rho_idx, theta_idx])
73 | else:
74 | np_idx = np.array(idx, dtype='int64')
75 | thr = abs(rho[np_idx[:,0]]-rho[rho_idx]) \
76 | +abs(rad_theta[np_idx[:,1]]-rad_theta[theta_idx])*5
77 | if np.min(thr) > threshold :
78 | idx.append([rho_idx, theta_idx])
79 | else:
80 | hough[rho_idx, theta_idx] = 0
81 | idx = np.array(idx, dtype='int64')
82 |
83 | element_rho = rho[idx[:,0]]
84 | element_theta = rad_theta[idx[:,1]]
85 |
86 | return idx, element_rho, element_theta
87 |
88 | idx, element_rho, element_theta = select_lines(hough_space, rad_theta, rho, num=10, threshold=20)
89 |
90 | plt.figure(figsize=(6,9))
91 | str_hough_space = hough_space*3 #3, 200
92 | str_hough_space[str_hough_space>255] = 255
93 | plt.imshow(str_hough_space, cmap='jet')
94 | plt.plot(idx[:,1], idx[:,0], 'wo')
95 | plt.title('Hough Space')
96 | plt.xlabel('Angles (degrees)')
97 | plt.ylabel('Distance (pixels)')
98 | plt.axis('off')
99 | plt.show()
100 |
101 | #%% draw lines
102 |
103 | m = - np.cos(element_theta)/np.sin(element_theta)
104 | b = element_rho / np.sin(element_theta)
105 |
106 | plt.figure()
107 | plt.imshow(bin_img, cmap='gray')
108 | for i in range(len(m)):
109 | for c in range(C):
110 | y = int(m[i]*c+b[i])
111 | if y >= 0 and y < R:
112 | plt.plot(c, y, marker='.', color='red')
113 | for r in range(R):
114 | x = int((r-b[i])/m[i])
115 | if x >=0 and x < C:
116 | plt.plot(x, r, marker='.', color='red')
117 | plt.title('Detecting lines')
118 | plt.show()
119 |
120 | #%% filter lines
121 |
122 | grad = []
123 |
124 | for i in range(len(m)):
125 | if np.tan(np.deg2rad(-10)) < m[i] and m[i] < np.tan(np.deg2rad(10)):
126 | grad.append([m[i], b[i]])
127 |
128 |
129 | plt.figure()
130 | plt.imshow(bin_img, cmap='gray')
131 | for i in range(len(grad)):
132 | for c in range(C):
133 | y = int(grad[i][0]*c+grad[i][1])
134 | if y >= 0 and y < R:
135 | plt.plot(c, y, marker='.', color='red')
136 | for r in range(R):
137 | x = int((r-grad[i][1])/grad[i][0])
138 | if x >=0 and x < C:
139 | plt.plot(x, r, marker='.', color='red')
140 | plt.title('Filter lines')
141 | plt.show()
142 |
143 |
144 |
--------------------------------------------------------------------------------
/09 Hough transform/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jstar0525/MachineVision/d40374034e0937a5bb86dde7305fa85c4df8e19e/09 Hough transform/test.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MachineVision
2 |
3 | ## [1. Connected-component labeling](./01%20Connected-component%20labeling)
4 |
5 |
6 | ## [2. Distance transform](./02%20Distance%20transform)
7 |
8 |
9 | ## [3. Contrast stretching](./03%20Contrast%20stretching)
10 |
11 |
12 | ## [4. Histogram equalization](./04%20Histogram%20equalization)
13 |
14 |
15 | ## [5. Median filtering](./05%20Median%20filtering)
16 |
17 |
18 | ## [6. Edge detection](./06%20Edge%20Detection)
19 |
20 |
21 | ## [7. Frequency domain filtering](./07%20Frequency%20domain%20filtering)
22 |
23 |
24 | ## [8. Convolution theorem](./08%20Convolution%20theorem)
25 |
26 |
27 | ## [9. Hough transform](./09%20Hough%20transform)
--------------------------------------------------------------------------------