How can I detect horizontal black lines using ImageMagick?
So I have what is essentially a TIFF table. There is a certain uniformity to it ... for example, all column widths are the same. I want to strip this sheet of the width of the known columns and basically create many small graphic files, one for each cell, and run OCR on them and save them to the database. The problem is that the horizontal lines don't have the same height, so I need to use some kind of graphics library command to check if each pixel has the same color (i.e. Black). And if so, then I know I have reached the height limit for the cell. How can I do it? (I am using RMagick)
a source to share
Use image#get_pixel
: http://www.simplesystems.org/RMagick/doc/image2.html#get_pixels
Warning. These documents are old, so they may be changed in new versions. Look at your own rdocs using $ gem server
, assuming they have rdocs.
image#rows
gives you the height of the image, then you can do something like (untested):
def black_line?(pixels)
pixels.each do |pixel|
unless pixel.red == 0 && pixel.green == 0 && pixel.blue == 0
return false
end
end
true
end
black_line_heights = []
height = image.rows
width = image.columns
height.times do |y|
pixels = image.get_pixel(0,y,width,1)
black_line_heights << y if black_line?(pixels)
end
Please keep in mind that I am not sure about the api. A look at the old docs and I can't verify it now. But this is similar to the general approach you would take. BTW, it assumes that line borders are 1 pixel thick. If not, change 1
to the actual thickness and that might be enough to make it work as you expect.
a source to share
Ehsanul had it almost right ... a get_pixels call that takes x, y, w, h as arguments and returns an array of those pixels. If size 1 is fat, you end up with a nice one-dimensional array.
Since the black in the document can change, I slightly modified the Ehsanul method to determine if consecutive pixels were of roughly the same color. Take 100px or so, this is probably the line:
def solid_line?(pixels, opt={}, black_val = 10)
last_pixel = nil
thresh = opt[:threshold].blank? ? 4 : opt[:threshold]
pixels.each do |pix|
pixel = [pix.red, pix.green, pix.blue]
if last_pixel != nil
return false if pixel.reject{|p| (p-last_pixel[pixel.index(p)]).abs < thresh && p < black_val}.length > 0
end
last_pixel = pixel
end
true
end
a source to share