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

159
LINES

< > BotCompany Repo | #398 // Magic Wand Algorithm (optimizing)

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  
    expandRight(image, r)
43  
    if tooLarge(r) then return nil end
44  
    expandBottom(image, r)
45  
    if tooLarge(r) then return nil end
46  
    if compareTables(last, r) then
47  
      if r.width >= minSize.width and r.height >= minSize.width then
48  
        rectangles[r] = true
49  
        return r
50  
      else
51  
        return nil
52  
      end
53  
    end
54  
  end
55  
end
56  
57  
function tooLarge(r)
58  
  return maxSize ~= nil and (r.width > maxSize.width or r.height > maxSize.height)
59  
end
60  
61  
function expandLeft(image, r)
62  
  local newX = math.max(r.x - wandSize, 0)
63  
  if newX == r.x then return end
64  
  newX = searchFromLeft(image, newRectangle(newX, r.y, r.x-newX, r.height))
65  
  r.width = r.width+r.x-newX
66  
  r.x = newX
67  
end
68  
69  
function searchFromLeft(image, r)
70  
  for x = r.x, r.x+r.width-1 do
71  
    if regionNotEmpty(image, newRectangle(x, r.y, 1, r.height)) then
72  
      return x
73  
    end
74  
  end
75  
  return r.x+r.width
76  
end
77  
78  
function expandRight(image, r)
79  
  local newX = math.min(r.x + r.width + wandSize, image.width)
80  
  if newX == r.x+r.width then return end
81  
  newX = searchFromRight(image, newRectangle(r.x+r.width, r.y, newX-(r.x+r.width), r.height))
82  
  r.width = newX-r.x
83  
end
84  
85  
function searchFromRight(image, r)
86  
  for x = r.x+r.width-1, r.x, -1 do
87  
    if regionNotEmpty(image, newRectangle(x, r.y, 1, r.height)) then
88  
      return x+1
89  
    end
90  
  end
91  
  return r.x
92  
end
93  
94  
function expandTop(image, r)
95  
  local newY = math.max(r.y - wandSize, 0)
96  
  if newY == r.y then return end
97  
  newY = searchFromTop(image, newRectangle(r.x, newY, r.width, r.y-newY))
98  
  r.height = r.height+r.y-newY
99  
  r.y = newY
100  
end
101  
102  
function searchFromTop(image, r)
103  
  for y = r.y, r.y+r.height-1 do
104  
    if regionNotEmpty(image, newRectangle(r.x, y, r.width, 1)) then
105  
      return y
106  
    end
107  
  end
108  
  return r.y+r.height
109  
end
110  
111  
function expandBottom(image, r)
112  
  local newY = math.min(r.y + r.height + wandSize, image.height)
113  
  if newY == r.y+r.height then return end
114  
  newY = searchFromBottom(image, newRectangle(r.x, r.y + r.height, r.width, newY-(r.y+r.height)))
115  
  r.height = newY-r.y
116  
end
117  
118  
function searchFromBottom(image, r)
119  
  for y = r.y+r.height-1, r.y, -1 do
120  
    if regionNotEmpty(image, newRectangle(r.x, y, r.width, 1)) then
121  
      return y+1
122  
    end
123  
  end
124  
  return r.y
125  
end
126  
127  
-- we're looking for dark pixels this time
128  
function regionNotEmpty(image, r)
129  
  --return image.clip(rectangle).anyPixelBrighterThan(threshold)
130  
  for y=r.y, r.y+r.height-1 do
131  
    for x=r.x, r.x+r.width-1 do
132  
      if bright(rgb(image.getInt(x, y))) < threshold then
133  
        return true
134  
      end
135  
    end
136  
  end
137  
  return false
138  
end
139  
140  
141  
function recttostring(r)
142  
  return r.x..", "..r.y..", "..r.x+r.width..", "..r.y+r.height
143  
end
144  
145  
function magicWandAll(image)
146  
  local allrects = {}
147  
148  
  for y = 0, image.height-1, 2 do
149  
    for x = 0, image.width-1, 2 do
150  
      local r = magicWand(image, x, y)
151  
      
152  
      if r then
153  
        allrects[recttostring(r)] = true
154  
      end
155  
    end
156  
  end
157  
  
158  
  return allrects
159  
end

Author comment

Began life as a copy of #369

test run  test run with input  download  show line numbers   

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

No comments. add comment

Snippet ID: #398
Snippet name: Magic Wand Algorithm (optimizing)
Eternal ID of this version: #398/1
Text MD5: 118d7f99c02fdc09a4f53a82dda704cb
Author: stefan
Category: image recognition
Type: Lua code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2015-02-05 00:16:59
Source code size: 3870 bytes / 159 lines
Pitched / IR pitched: No / Yes
Views / Downloads: 669 / 159
Referenced in: [show references]