get("#121") -- compareTables
get("#348") -- bright and rgb
maxSize = {width=100, height=50}
minSize = {width=4, height=4}
threshold = 0.5
wandSize = 2 -- magic wand size
local rectangles, img
function cloneRectangle(r)
return newRectangle(r.x, r.y, r.width, r.height)
end
function newRectangle(x, y, w, h)
return {x=x, y=y, width=w, height=h}
end
function contains(r, x, y)
return x >= r.x and y >= r.y and x < r.x+r.width and y < r.y+r.width
end
function seen(x, y)
for r, _ in pairs(rectangles) do
if contains(r, x, y) then
return true
end
end
return false
end
-- returns rectangle
function magicWand(image, x, y)
if image ~= img then
img, rectangles = image, {}
end
if seen(x, y) then return nil end
local r = newRectangle(x, y, 1, 1)
while true do
local last = cloneRectangle(r)
expandRight(image, r)
if tooLarge(r) then return nil end
expandBottom(image, r)
if tooLarge(r) then return nil end
if compareTables(last, r) then
if r.width >= minSize.width and r.height >= minSize.width then
rectangles[r] = true
return r
else
return nil
end
end
end
end
function tooLarge(r)
return maxSize ~= nil and (r.width > maxSize.width or r.height > maxSize.height)
end
function expandLeft(image, r)
local newX = math.max(r.x - wandSize, 0)
if newX == r.x then return end
newX = searchFromLeft(image, newRectangle(newX, r.y, r.x-newX, r.height))
r.width = r.width+r.x-newX
r.x = newX
end
function searchFromLeft(image, r)
for x = r.x, r.x+r.width-1 do
if regionNotEmpty(image, newRectangle(x, r.y, 1, r.height)) then
return x
end
end
return r.x+r.width
end
function expandRight(image, r)
local newX = math.min(r.x + r.width + wandSize, image.width)
if newX == r.x+r.width then return end
newX = searchFromRight(image, newRectangle(r.x+r.width, r.y, newX-(r.x+r.width), r.height))
r.width = newX-r.x
end
function searchFromRight(image, r)
for x = r.x+r.width-1, r.x, -1 do
if regionNotEmpty(image, newRectangle(x, r.y, 1, r.height)) then
return x+1
end
end
return r.x
end
function expandTop(image, r)
local newY = math.max(r.y - wandSize, 0)
if newY == r.y then return end
newY = searchFromTop(image, newRectangle(r.x, newY, r.width, r.y-newY))
r.height = r.height+r.y-newY
r.y = newY
end
function searchFromTop(image, r)
for y = r.y, r.y+r.height-1 do
if regionNotEmpty(image, newRectangle(r.x, y, r.width, 1)) then
return y
end
end
return r.y+r.height
end
function expandBottom(image, r)
local newY = math.min(r.y + r.height + wandSize, image.height)
if newY == r.y+r.height then return end
newY = searchFromBottom(image, newRectangle(r.x, r.y + r.height, r.width, newY-(r.y+r.height)))
r.height = newY-r.y
end
function searchFromBottom(image, r)
for y = r.y+r.height-1, r.y, -1 do
if regionNotEmpty(image, newRectangle(r.x, y, r.width, 1)) then
return y+1
end
end
return r.y
end
-- we're looking for dark pixels this time
function regionNotEmpty(image, r)
--return image.clip(rectangle).anyPixelBrighterThan(threshold)
for y=r.y, r.y+r.height-1 do
for x=r.x, r.x+r.width-1 do
if bright(rgb(image.getInt(x, y))) < threshold then
return true
end
end
end
return false
end
function recttostring(r)
return r.x..", "..r.y..", "..r.x+r.width..", "..r.y+r.height
end
function magicWandAll(image)
local allrects = {}
for y = 0, image.height-1, 2 do
for x = 0, image.width-1, 2 do
local r = magicWand(image, x, y)
if r then
allrects[recttostring(r)] = true
end
end
end
return allrects
endBegan 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: | 1038 / 242 |
| Referenced in: | [show references] |