- implement extract-words:
(import [os.path :as path]) (path/exists "test.txt") ;;=> false (import [cv2 :as cv2]) (def image (cv2/imread "test/resources/ex1.jpg")) (defn extract-word-images [page-filename] (let [image (cv2/imread page-filename) gray (cv2/cvtColor image cv2/COLOR_BGR2GRAY) blur (cv2/GaussianBlur gray [5 5] 0) thresh (second (cv2/threshold blur 0 255 (+ cv2/THRESH_BINARY_INV cv2/THRESH_OTSU))) kernel (cv2/getStructuringElement cv2/MORPH_RECT [7 7]) dilate (cv2/dilate thresh kernel ** :iterations 1) cnts* (cv2/findContours dilate cv2/RETR_EXTERNAL cv2/CHAIN_APPROX_SIMPLE) cnts (if (= (count cnts*) 2) (first cnts*) (second cnts*))] (map (fn [contour] (let [[x y w h] (cv2/boundingRect contour)] (aget image #py ((slice y (+ y h)) (slice x (+ x w)))) )) cnts))) (def words (extract-word-images "test/resources/ex1.jpg")) (cv2/boundingRect (first cnts)) ;; => #py (2204 3239 10 8) (let [[x y w h] (cv2/boundingRect (first cnts))] x) ;; => 2204 (class (first cnts)) ;; => <class 'numpy.ndarray'> (first words) ;; => array([[[247, 247, 247], ;; [238, 238, 238], ;; [229, 229, 229], ;; [223, 223, 223], ;; [216, 216, 216], ;; [212, 212, 212], ;; [202, 202, 202], ;; [188, 188, 188], ;; [175, 175, 175], ;; [169, 169, 169]], ;; [[242, 242, 242], ;; [228, 228, 228], ;; [214, 214, 214], ;; [205, 205, 205], ;; [192, 192, 192], ;; [188, 188, 188], ;; [183, 183, 183], ;; [180, 180, 180], ;; [179, 179, 179], ;; [181, 181, 181]], ;; [[226, 226, 226], ;; [211, 211, 211], ;; [198, 198, 198], ;; [189, 189, 189], ;; [162, 162, 162], ;; [161, 161, 161], ;; [161, 161, 161], ;; [163, 163, 163], ;; [167, 167, 167], ;; [174, 174, 174]], ;; [[202, 202, 202], ;; [187, 187, 187], ;; [175, 175, 175], ;; [168, 168, 168], ;; [142, 142, 142], ;; [145, 145, 145], ;; [151, 151, 151], ;; [159, 159, 159], ;; [170, 170, 170], ;; [180, 180, 180]], ;; [[182, 182, 182], ;; [168, 168, 168], ;; [159, 159, 159], ;; [154, 154, 154], ;; [151, 151, 151], ;; [156, 156, 156], ;; [166, 166, 166], ;; [178, 178, 178], ;; [191, 191, 191], ;; [203, 203, 203]], ;; [[175, 175, 175], ;; [165, 165, 165], ;; [159, 159, 159], ;; [155, 155, 155], ;; [168, 168, 168], ;; [175, 175, 175], ;; [186, 186, 186], ;; [199, 199, 199], ;; [211, 211, 211], ;; [220, 220, 220]], ;; [[183, 183, 183], ;; [178, 178, 178], ;; [175, 175, 175], ;; [173, 173, 173], ;; [180, 180, 180], ;; [187, 187, 187], ;; [199, 199, 199], ;; [211, 211, 211], ;; [220, 220, 220], ;; [225, 225, 225]], ;; [[199, 199, 199], ;; [198, 198, 198], ;; [198, 198, 198], ;; [197, 197, 197], ;; [192, 192, 192], ;; [200, 200, 200], ;; [212, 212, 212], ;; [225, 225, 225], ;; [233, 233, 233], ;; [236, 236, 236]]], dtype=uint8) (cv2/imwrite "tmp/words/word000.png" (first words)) (format "test %03d" 1) ;; => "test 001" (map-indexed #(println (str %1 "-" %2)) cnts) (defn save-words-image [words outdir] (map-indexed #(cv2/imwrite (format "%s/word%03d.png" outdir %1) %2) words)) (save-words-image words "tmp/words") (defmacro mget [m r1 r2 c1 c2] `(aget ~m (python/tuple [(python/slice ~r1 ~r2) (python/slice ~c1 ~c2)])))
- incerc sa reduc grosimea liniilor la un pixel:
(import [cv2 :as cv2] [numpy :as np] [matplotlib :as matp] [matplotlib.pyplot :as plt]) ;; (matp/use "tkagg") (def img (cv2/imread "test/resources/orig.png")) (def edges (cv2/Canny img 100 200)) (defn show [img] (plt/imshow img ** :cmap "gray") (plt/show)) (show img) (show edges) ;; Valuerror: 'gtkagg' is not a valid value for backend; supported values are ['gtk3agg', 'gtk3cairo', 'gtk4agg', 'gtk4cairo', 'macosx', 'nbagg', 'notebook', 'qtagg', 'qtcairo', 'qt5agg', 'qt5cairo', 'tkagg', 'tkcairo', 'webagg', 'wx', 'wxagg', 'wxcairo', 'agg', 'cairo', 'pdf', 'pgf', 'ps', 'svg', 'template']
- continui cu modificarea parametrilor de la canny:
(import [cv2 :as cv2] [numpy :as np] [matplotlib :as matp] [matplotlib.pyplot :as plt]) (def img (cv2/imread "test/resources/orig.png")) (defn show [img] (plt/imshow img ** :cmap "gray") (plt/show)) (def edges (cv2/Canny img 100 200)) (show edges)
- incerc noi methode:
(import [cv2 :as cv2]) (require '[steno.utils :as utl]) (def img (cv2/imread "test/resources/words/word010.png")) (utl/show img)
- testez metoda gasita in https://docs.opencv.org/3.4/d9/d61/tutorial_py_morphological_ops.html
(import [cv2 :as cv2] [numpy :as np]) (require '[steno.utils :as utl]) (def img (cv2/imread "test/resources/words/word010.png")) (utl/show img) (def invert (cv2/bitwise_not img)) (utl/show invert) (def kernel (np/ones [5 5] np/uint8)) (def erosion (cv2/erode invert kernel ** :iterations 1)) (utl/show erosion)
- testez metoda gasita in https://theailearner.com/tag/skeletonization-opencv/:
(import [cv2 :as cv2] [numpy :as np]) (require '[steno.utils :as utl]) (def img (cv2/imread "test/resources/words/word010.png")) (utl/show img) ;; inversez imaginea (def invert (cv2/bitwise_not img)) (utl/show invert) ;; incerc o filtrare intai kernel = np.ones((5,5),np.float32)/25 dst = cv.filter2D(img,-1,kernel) (def kernel (/ (np/ones [5 5] np/float32) 25)) (def filter-img (cv2/filter2D invert -1 kernel)) (utl/show filter-img) ;; blur (def blur (cv2/blur invert [5,5])) (utl/show blur) ;; skeletonization (def kernel (cv2/getStructuringElement cv2/MORPH_CROSS [3 3])) (def thin (np/zeros (.- blur shape) ** :dtype "uint8")) (cv2/countNonZero thin) (def img2 (loop [image blur result thin] (println "step") (if (zero? (cv2/countNonZero image)) result (let [erode (cv2/erode image kernel) opening (cv2/morphologyEx erode cv2/MORPH_OPEN kernel) subset (- erode opening)] (recur erode (cv2/bitwise_or subset result)))))) ;; binary (def bin-image (second (cv2/threshold blur 175 255 cv2/THRESH_BINARY))) (utl/show bin-image)
- incerc scikit
(import [cv2 :as cv2] [numpy :as np] [skimage.morphology :as skim]) (require '[steno.utils :as utl]) (def img (-> (cv2/imread "test/resources/words/word010.png") (cv2/bitwise_not) (cv2/blur [5,5]))) (import [skimage.morphology :as skim]) (def img1 (skim/skeletonize img)) (import [skimage.util :as skiu]) (def img2 (skiu/img_as_ubyte img1)) (utl/show img2) (def img (-> (cv2/imread "test/resources/words/word010.png") (cv2/bitwise_not) (cv2/blur [5,5]) (skim/skeletonize) (skiu/img_as_ubyte))) (utl/show img)
- afiseaza o matrice binara:
;; import numpy as np ;; import matplotlib.pyplot as plt ;; # create a random binary bidimensional matrix of size 10x10 ;; matrix = np.random.randint(2, size=(10, 10)) ;; plt.imshow(matrix, cmap='binary', interpolation='nearest') ;; plt.show() (import [numpy.random :as np] [cv2 :as cv2] [matplotlib :as matp] [matplotlib.pyplot :as plt]) (matp/use "tkagg") (def matrix (np/randint 2 ** :size [10 10])) (plt/imshow matrix ** :cmap "gray" :interpolation "nearest") (plt/show) (defn show-matrix [mat] (plt/imshow mat ** :cmap "gray" :interpolation "nearest") (plt/show)) (show-matrix matrix) (defn convert-cell [val] (println (apply + val)) (if (zero? (apply + val)) 0 1)) (def img (cv2/imread "test/resources/words/word010.png")) (def word010 (mapv #(mapv convert-cell %) img)) (show-matrix word010) (def bw (cv2/threshold img 127 255 cv2/THRESH_BINARY)) (require '[steno.utils :as utl]) (utl/show bw) (let [shape (.- img shape)] (def rows (first shape)) (def cols (second shape))) ;; => #py (62 256 3) (zero? (apply + (aget img 2 2))) ;; => np.uint8(0) (defn convert-image [img] (let [[rows cols _] (.- img shape)] (mapv (fn [i] (mapv (fn [j] (if (bool (zero? (apply + (aget img i j)))) 0 1)) (range 0 cols))) (range 0 rows)))) (def word010 (convert-image img)) (show-matrix word010) # 8 151-161 (bool (zero? (apply + (aget img 8 151)))) ;; => false (bool (zero? (apply + (aget img 8 150)))) ;; => true ;; => np.False_
- continui implementarea converter:
(def directions [[ 0 1] ; E [ 1 1] ; SE [ 1 0] ; S [ 1 -1] ; SV [ 0 -1] ; V [-1 -1] ; NV [-1 0] ; N [-1 1] ; NE ]) (def matrix [[0 0 0] [0 1 1] [0 0 0]]) (aget matrix 1 1) ;; => 1 (defn get-neighbor [mat [r c] [dr dc]] (try (aget mat (+ r dr) (+ c dc)) (catch Exception e 0))) (get-neighbor matrix [1 1] (first directions)) ;; => 1 (get-neighbor matrix [1 1] (nth directions 2)) ;; => 0 (get-neighbor matrix [0 0] (nth directions 4)) ;; => 0 (defn get-cell-number [mat point] (reduce (fn [[count num] dir] (let [v (get-neighbor mat point dir)] [(+ count v) (+ (* num 2) v)])) [0 0] directions)) (get-cell-number matrix [1 1]) ;; => [1 128] (format "%x" 128) ;; => "80" (get-cell-number matrix [2 1]) ;; => [3 11] (format "%x" 11) ;; => "b" ;; 1011 (doseq [d directions] (println (get-neighbor matrix [2 1] d))) (def mat1 [[6 7 8] [5 0 1] [4 3 2]]) (mapv #(get-neighbor mat1 [1 1] %) directions) ;; => [1 2 3 4 5 6 7 8] (mapv #(get-neighbor mat1 [2 1] %) directions) ;; => [2 0 0 0 4 5 0 1]
- continui implementarea converter:
(require '[steno.converter :as cnv] '[steno.utils :as utl]) (defn get-neighbor [mat [r c] [dr dc]] (let [nr (+ r dr) nc (+ c dc)] (try [[nr nc] (aget mat nr nc)] (catch Exception e [[-1 -1] 0])))) (defn get-cell-number-and-neighbors [mat point] (reduce (fn [[neighbors num] dir] (let [[np v] (get-neighbor mat point dir)] [(if (zero? v) neighbors (conj neighbors np)) (+ (* num 2) v)])) [#{} 0] cnv/directions)) (def mat1 [[6 7 8] [5 0 1] [4 3 2]]) (mapv #(get-neighbor mat1 [1 1] %) cnv/directions) ;; => [[[1 2] 1] [[2 2] 2] [[2 1] 3] [[2 0] 4] [[1 0] 5] [[0 0] 6] [[0 1] 7] [[0 2] 8]] (def mat2 [[1 1 1] [1 0 1] [1 1 1]]) (get-cell-number-and-neighbors mat2 [1 1]) ;; => [#{[1 2] [2 2] [1 0] [0 2] [2 0] [0 1] [0 0] [2 1]} 255] (defn get-liniar-sequence [mat start-cell prev-cell acc] (let [[neighbors val] (get-cell-number-and-neighbors mat start-cell) new-neighbors (disj neighbors prev-cell) new-acc (conj acc val) num (count new-neighbors)] (cond (zero? num) [[-1 -1] start-cell new-acc] (= num 1) (get-liniar-sequence mat (first new-neighbors) start-cell new-acc) :else [start-cell prev-cell acc]))) (defn get-start-cell [mat strict?] (let [max-column (count mat) max-row (count (first mat))] (loop [column 0 row 0] (let [[neighbors _] (get-cell-number-and-neighbors mat [row column]) n (count neighbors)][] (if (or (and strict? (= 1 n)) (> n 0)) [row column] (let [new-row (+ row 1) new-column (if (= new-row max-row) (+ column 1) column) new-row (if (= new-row max-row) 0 new-row)] (if (= new-column max-column) [-1 -1] (recur new-column new-row)))))))) (import [cv2 :as cv2]) (def word010 (cnv/image->matrix (cv2/imread "test/resources/words/word010.png"))) (utl/show-matrix word010) (get-start-cell word010 true) ;; => [42 6] (get-liniar-sequence word010 [42 6] [-1 -1] []) ;; => [[34 150] [35 149] [64 128 136 9 144 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 9 144 136 136 72 132 9 144 136 136 136 136 136 136 136 136 136 136 136 136 136 72 132 136 72 132 136 136 136 136 136 136 136 136 72 132 136 136 136 9 144 136 136 136 136 72 132 136 72 68 68 68 68 36 66 132 136 136 136 136 136 136 136 136 9 144 9 144 136 9 144 9 144 136 136 136 136 9 144 136 136 9 144 136 136 136 9 144 136 136 9 144 136 136 136 9 17 17 144 136 136 9 144 136 136 9 144 9 17 18 33]]
(def neighbors
(-> (get-cell-number-and-neighbors word010 [34 150])
first
(disj [35 149])))
;; => #{[33 149] [34 151]}
(def seq1 (get-liniar-sequence word010 [33 149] [34 150] []))
;; => [[29 177] [28 177] [66 34 36 66 36 68 68 68 66 34 34 34 34 34 36 66 34 34 33 18 33 17 17 17 144 136 9 144 136 136 136 136 136 136 136 136 136 72 132 136 136 136 136 136 136 72 132 72 68 68 68 68 36 34 34 34 34 66 36 18 33 34 66 36 34 34]]
(def seq2 (get-liniar-sequence word010 [34 151] [34 150] []))
seq2
;; => [[30 176] [31 175] [136 136 136 136 136 136 136 72 5 144 136 136 136 136 136 136 136 9 17 144 136 136 9 144 9]]
(defn get-next-neighbors
[mat start-cell prev-cell]
(-> (get-cell-number-and-neighbors word010 start-cell)
first
(disj prev-cell)))
(get-next-neighbors word010 [29 177] [28 177])
;; => #{[30 177] [30 176]}
(get-next-neighbors word010 [30 176] [31 175])
;; => #{[30 177] [29 177]}
(get-cell-number-and-neighbors word010 [30 177])
;; => [#{[30 176] [31 178] [29 177]} 74]
(require '[basilisp.set :as set])
(def start-cell [34 150])
(def prev-cell [35 149])
(def neighbors (get-next-neighbors word010 start-cell prev-cell))
;; => #{[33 149] [34 151]}
(def res (map (fn [cell]
(get-liniar-sequence word010 cell start-cell []))
neighbors))
;; => ([[29 177] [28 177] [66 34 36 66 36 68 68 68 66 34 34 34 34 34 36 66 34 34 33 18 33 17 17 17 144 136 9 144 136 136 136 136 136 136 136 136 136 72 132 136 136 136 136 136 136 72 132 72 68 68 68 68 36 34 34 34 34 66 36 18 33 34 66 36 34 34]] [[30 176] [31 175] [136 136 136 136 136 136 136 72 5 144 136 136 136 136 136 136 136 9 17 144 136 136 9 144 9]])
(def seqs (mapv #(nth % 2) res))
;; => [[66 34 36 66 36 68 68 68 66 34 34 34 34 34 36 66 34 34 33 18 33 17 17 17 144 136 9 144 136 136 136 136 136 136 136 136 136 72 132 136 136 136 136 136 136 72 132 72 68 68 68 68 36 34 34 34 34 66 36 18 33 34 66 36 34 34] [136 136 136 136 136 136 136 72 5 144 136 136 136 136 136 136 136 9 17 144 136 136 9 144 9]]
(def new-prevs (set (map first res)))
(def next-neighbors
(->> res
(map (fn [[start prev _]]
(get-next-neighbors word010 start prev)))
(apply set/union)
(set)))
;; => #{[30 177] [30 176] [29 177]}
(def next (first (set/difference next-neighbors new-prevs)))
(def next-res (get-cell-number-and-neighbors word010 next))
;; => [#{[30 176] [31 178] [29 177]} 74]
(def new-start-cell (-> (first next-res)
(set/difference next-neighbors)
first))
(defn get-parallel-sequence
[mat start prev]
(let [neighbors (get-next-neighbors mat start prev)
res (map (fn [cell]
(get-liniar-sequence mat cell start []))
neighbors)
seqs (mapv #(nth % 2) res)
new-prevs (set (map first res))
next-neighbors (->> res
(map (fn [[s p _]]
(get-next-neighbors mat s p)))
(apply set/union)
(set))
new-prev (first (set/difference next-neighbors new-prevs))
[new-neighbors _] (get-cell-number-and-neighbors mat new-prev)
new-start (-> new-neighbors
(set/difference next-neighbors)
first)]
[new-start new-prev seqs]))
(defn matrix->numseq
[mat start-cell]
(loop [start start-cell
prev dummy-cell
acc []]
(let [[new-start new-prev seq] (get-liniar-sequence mat start prev [])]
(if (= new-start dummy-cell)
(conj acc seq)
(let [[st pr pseqs] (get-parallel-sequence mat new-start new-prev)]
(recur st pr (conj acc seq pseqs)))))))
(matrix->numseq word010 [42 6])
;; => [[64 128 136 9 144 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 9 144 136 136 72 132 9 144 136 136 136 136 136 136 136 136 136 136 136 136 136 72 132 136 72 132 136 136 136 136 136 136 136 136 72 132 136 136 136 9 144 136 136 136 136 72 132 136 72 68 68 68 68 36 66 132 136 136 136 136 136 136 136 136 9 144 9 144 136 9 144 9 144 136 136 136 136 9 144 136 136 9 144 136 136 136 9 144 136 136 9 144 136 136 136 9 17 17 144 136 136 9 144 136 136 9 144 9 17 18 33] [[66 34 36 66 36 68 68 68 66 34 34 34 34 34 36 66 34 34 33 18 33 17 17 17 144 136 9 144 136 136 136 136 136 136 136 136 136 72 132 136 136 136 136 136 136 72 132 72 68 68 68 68 36 34 34 34 34 66 36 18 33 34 66 36 34 34] [136 136 136 136 136 136 136 72 5 144 136 136 136 136 136 136 136 9 17 144 136 136 9 144 9]] [132 72 132 136 136 72 132 136 136 136 72 132 72 132 136 136 136 136 72 132 136 136 72 132 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 136 9 17 17 17 17 17 17 17 17 17 18 34 33 18 34 34 32]]