Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

163
LINES

< > BotCompany Repo | #369 // Magic Wand Algorithm (optimized & including magicWandAll)

Lua code

1  
get("#121") -- compareTables
2  
get("#348") -- bright and rgb
3  
4  
maxSize = {width=100, height=50}
5  
minSize = {width=4, height=4}
6  
threshold = 0.5
7  
wandSize = 2 -- magic wand size
8  
9  
local rectangles, img
10  
11  
function cloneRectangle(r)
12  
  return newRectangle(r.x, r.y, r.width, r.height)
13  
end
14  
15  
function newRectangle(x, y, w, h)
16  
  return {x=x, y=y, width=w, height=h}
17  
end
18  
19  
function contains(r, x, y)
20  
  return x >= r.x and y >= r.y and x < r.x+r.width and y < r.y+r.width
21  
end
22  
23  
function seen(x, y)
24  
  for r, _ in pairs(rectangles) do
25  
    if contains(r, x, y) then
26  
      return true
27  
    end
28  
  end
29  
return false
30  
end
31  
32  
-- returns rectangle
33  
function magicWand(image, x, y)
34  
  if image ~= img then
35  
    img, rectangles = image, {}
36  
  end
37  
  if seen(x, y) then return nil end
38  
  local r = newRectangle(x, y, 1, 1)
39  
  
40  
  while true do
41  
    local last = cloneRectangle(r)
42  
    expandLeft(image, r)
43  
    if tooLarge(r) then return nil end
44  
    expandTop(image, r)
45  
    if tooLarge(r) then return nil end
46  
    expandRight(image, r)
47  
    if tooLarge(r) then return nil end
48  
    expandBottom(image, r)
49  
    if tooLarge(r) then return nil end
50  
    if compareTables(last, r) then
51  
      if r.width >= minSize.width and r.height >= minSize.width then
52  
        rectangles[r] = true
53  
        return r
54  
      else
55  
        return nil
56  
      end
57  
    end
58  
  end
59  
end
60  
61  
function tooLarge(r)
62  
  return maxSize ~= nil and (r.width > maxSize.width or r.height > maxSize.height)
63  
end
64  
65  
function expandLeft(image, r)
66  
  local newX = math.max(r.x - wandSize, 0)
67  
  if newX == r.x then return end
68  
  newX = searchFromLeft(image, newRectangle(newX, r.y, r.x-newX, r.height))
69  
  r.width = r.width+r.x-newX
70  
  r.x = newX
71  
end
72  
73  
function searchFromLeft(image, r)
74  
  for x = r.x, r.x+r.width-1 do
75  
    if regionNotEmpty(image, newRectangle(x, r.y, 1, r.height)) then
76  
      return x
77  
    end
78  
  end
79  
  return r.x+r.width
80  
end
81  
82  
function expandRight(image, r)
83  
  local newX = math.min(r.x + r.width + wandSize, image.width)
84  
  if newX == r.x+r.width then return end
85  
  newX = searchFromRight(image, newRectangle(r.x+r.width, r.y, newX-(r.x+r.width), r.height))
86  
  r.width = newX-r.x
87  
end
88  
89  
function searchFromRight(image, r)
90  
  for x = r.x+r.width-1, r.x, -1 do
91  
    if regionNotEmpty(image, newRectangle(x, r.y, 1, r.height)) then
92  
      return x+1
93  
    end
94  
  end
95  
  return r.x
96  
end
97  
98  
function expandTop(image, r)
99  
  local newY = math.max(r.y - wandSize, 0)
100  
  if newY == r.y then return end
101  
  newY = searchFromTop(image, newRectangle(r.x, newY, r.width, r.y-newY))
102  
  r.height = r.height+r.y-newY
103  
  r.y = newY
104  
end
105  
106  
function searchFromTop(image, r)
107  
  for y = r.y, r.y+r.height-1 do
108  
    if regionNotEmpty(image, newRectangle(r.x, y, r.width, 1)) then
109  
      return y
110  
    end
111  
  end
112  
  return r.y+r.height
113  
end
114  
115  
function expandBottom(image, r)
116  
  local newY = math.min(r.y + r.height + wandSize, image.height)
117  
  if newY == r.y+r.height then return end
118  
  newY = searchFromBottom(image, newRectangle(r.x, r.y + r.height, r.width, newY-(r.y+r.height)))
119  
  r.height = newY-r.y
120  
end
121  
122  
function searchFromBottom(image, r)
123  
  for y = r.y+r.height-1, r.y, -1 do
124  
    if regionNotEmpty(image, newRectangle(r.x, y, r.width, 1)) then
125  
      return y+1
126  
    end
127  
  end
128  
  return r.y
129  
end
130  
131  
-- we're looking for dark pixels this time
132  
function regionNotEmpty(image, r)
133  
  --return image.clip(rectangle).anyPixelBrighterThan(threshold)
134  
  for y=r.y, r.y+r.height-1 do
135  
    for x=r.x, r.x+r.width-1 do
136  
      if bright(rgb(image.getInt(x, y))) < threshold then
137  
        return true
138  
      end
139  
    end
140  
  end
141  
  return false
142  
end
143  
144  
145  
function recttostring(r)
146  
  return r.x..", "..r.y..", "..r.x+r.width..", "..r.y+r.height
147  
end
148  
149  
function magicWandAll(image)
150  
  local allrects = {}
151  
152  
  for y = 0, image.height-1, 2 do
153  
    for x = 0, image.width-1, 2 do
154  
      local r = magicWand(image, x, y)
155  
      
156  
      if r then
157  
        allrects[recttostring(r)] = true
158  
      end
159  
    end
160  
  end
161  
  
162  
  return allrects
163  
end

Author comment

Began life as a copy of #363

test run  test run with input  download  show line numbers   

Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt, znullqslnikg

No comments. add comment

Snippet ID: #369
Snippet name: Magic Wand Algorithm (optimized & including magicWandAll)
Eternal ID of this version: #369/1
Text MD5: c93de8ac2039791bdd437ef966ef5e06
Author: stefan
Category: image recognition
Type: Lua code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2015-02-02 20:20:05
Source code size: 4001 bytes / 163 lines
Pitched / IR pitched: No / Yes
Views / Downloads: 638 / 165
Referenced in: [show references]