Closed chconnor closed 1 year ago
Interesting idea. I'll have to think about it.
I do follow the logic of both "one" and "minus" consisting of a segment, and that they should be of sufficient size that a "scanline" would be accepted. For "one", checking the width suffices; for a "minus", checking the height suffices. This does seem useful.
Just extending -n, --number-pixels NUMBER
to apply to "one" and "minus" risks breaking existing setups, thus I'd probably introduce a new option to activate this.
I'd say I'd like similar functionality for decimal separators, too, but that should probably use a separate value and thus a separate option to specify the minimum dimensions.
Yet another approach could be to only accept "digits" during segmentation if they are of some minimum width and height. This would pertain to any type of "digit", including decimal separators.
I do not expect to find time to look into this until the next weekend, and cannot promise anything.
Thanks!
Yeah, I was going to suggest a minimum digit segmentation width until I saw the -n. Makes sense that using -n might break old usage, and new options would be great, too. Maybe a separate min W/H from decimal points, though? I'm no 7-segment expert, but it would seem like some decimal points are pretty small compared to digits?
Anyway, thanks again for considering!
I am currently considering adding an option -N, --min-segment=SIZE
that would work for both scanline and ratio based recognition, but only when segments are used to create the character (digit), i.e., not for the decimal separator. In effect that means that -N
would extend -n
to also include the digit one and the minus sign.
Do you have one (or a few) example image(s) you could provide for testing where you would like to use the requested feature? Ideally with the command line you (would like to) use?
So it sounds like -N would not apply to overall segmentation (i.e. vertical red and blue lines in the debug images) but rather when scanning for individual segment elements within a potential digit?
With this image I get a good scan ("63.7") if I use this command:
ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 -i 5 remove_isolated 5 keep_pixels_filter 5 -d -1 -t 98 ssocr_demo2.jpg
If I use a simpler command:
ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 -d -1 -t 98 ssoc_demo2.jpg
...I understandably get .11.1....111111.111....1111.1._....11611.1.3_...7
because it picks up tons of noise, etc.
So the appeal of -N for me would just be the convenience to be able to say "ignore any potential digits narrower than X pixels when doing overall segmentation" -- I could skip learning all the noise parameters because it would neatly exclude all the small stuff:
ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 -N 10 -d -1 -t 98 ssocr_demo2.jpg
...though I guess that would then apply to decimal points, too. Maybe that's fine.
I suppose if it instead worked as a min size on individual segment scanning (as I think you described), but still did overall digit segmentation the way it does now, then it would still output a lot of .'s or _'s for the false-trigger "noise digits" found during segmentation? Or maybe -N could apply to both digit segmentation and segment scanning? Basically saying "this is the scale of real segments in this image, ignore everything smaller".
I guess that's basically the point of keep_pixels_filter, but it feels a little touchy to use sometimes. E.g. this outputs nothing because the filter generates white only:
ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 keep_pixels_filter 9 -d -1 -t 98 ssocr_demo2.jpg
...changing keep_pixels_filter to 8 works perfectly, and changing it to 7 generates a false decimal point based on noise. So it doesn't end up feeling like a safe way to process the noise away.
Anyway, not sure if this brainstorming is helpful as I only loosely understand the algorithm. :-) I have many more such images and can post some more if it's helpful, but they're all basically the same: relatively noisy and of the same device.
The keep_pixels_filter
and the similar set_pixels_filter
are simple generalizations of remove_isolated
. keep_pixels_filter 1
is identical to remove_isolated
. They use a 9x9 pixel grid centered on the current pixel (i.e., the current pixel and its 8 direct neighbors). They are intended for noise removal, working for small disconnected clusters of pixels.
The opening
command can work better when some such clusters touch. Another strategy for reliable recognition is to find a good -t
value, i.e., find both minimum and maximum values that work and use some value in the middle. With good image quality, -T
can be used instead of manually specifying a base threshold.
The following variants work for this image:
$ ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 opening -d -1 -t 98 ssocr_demo2.jpg
63.7
$ ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 -d -1 -t 80 ssocr_demo2.jpg
63.7
$ ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 -d -1 -T ssocr_demo2.jpg
63.7
I am not sure if applying the -n
value to "one" and "minus" is really helpful here. But I do have a first prototype implementation of -N
and plan to add this to ssocr
.
I'd expect that adjusting the segmentation step of the algorithm to ignore potential characters / digits below some minimum size or rather minimum dimensions (i.e., not minimum area) would be more helpful with the ssocr_demo2.jpg
image and a -t 98
setting. While I'd expect that you can find a better -t
setting than 98, that is not always the case. Thus after -N
I'd like to look into something like -M, --min-char-dims=W,H
to do just that.
Sounds good, and thanks for the tips!
(I had to use -t 98 there because some of the images in that series of images weren't consistent (LCD segments that were caught coming on/off as the shutter was open, so they were half-black, etc.) Some day I'll upgrade my setup to trigger off an Arduino so everything will be sync'ed properly.)
Just extending the -n
/--number-pixels
constraint to one and minus recognition, as the discussed -N
/-min-segment
does, turns small noise that is interpreted as one or minus into a digit / character with no segments (output character _
, exit code 1). This does not seem to help that much, but it is more correct (ssocr
cannot recognize the digit / character). Thus this could even be seen as a bug fix.
I could add an option to omit empty digits / characters, i.e., digits / characters with no set segments, similar to -C
/--omit-decimal-point
(ignored digits / characters would not result in a non-zero exit code).
That still leaves all the spurious decimal points in your example output from one of your comments above. Using -C
/--omit-decimal-point
to ignore them would also ignore the actual decimal point in the display. Something like the discussed -M
/--min-char-dims=WxH
(combined with -i
/--ignore-pixels
) might be more helpful, because it would not create many small digits / characters in the first place.
If you want to use a high threshold to mitigate timing issues, I would suggest you look into using opening
, possibly combined with -i
/--ignore-pixels
to ignore some noise during segmentation and -n
/--number-pixels
(or the planned -N
/-min-segment
) to ignore some noise inside each digit. The -M
/--min-char-dims
idea might also help.
An alternative approach could be to rely on the exit code of ssocr
(or on some output specifics, e.g., _
or too many or too few characters (I think you expect between 3 and 5 characters, i.e., one decimal point and two to four digits)) to detect a recognition failure and immediately take another picture to re-attempt recognition. This would allow to use ssocr
settings that remove all the noise in good pictures. (It might help to allow specifying a range for the number of digits… yet another idea for improving ssocr
.)
I have added -N, --min-segment=SIZE
to the development version of ssocr
in the Git repository. It works as expected with your example.
Without -N
, there are many spurious one and decimal point recognition results:
$ ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 -d -1 -t 98 ssocr_demo2.jpg
.11.1....111111.111....1111.1._....11611.1.3_...7
With -N 10
, spurious one recognition results are turned into unknown digits (shown with _
).:
$ ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 -d -1 -t 98 -N10 ssocr_demo2.jpg
.__._....__..__..__......_.._._....._6.....3_...7
Thanks for the added feature!
And now for the next step: I have added the option -M, --min-char-dims=WxH
to the development version of ssocr
in the Git repository. This does allow to just drop too small potential digits and thus recognize the number in your example image:
$ ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 -d-1 -t98 -i1 -n2 -M 10x10 ssocr_demo2.jpg
63.7
When the number of digits is know, as with a single example image, this can be specified instead of using -1
for an unspecified number of digits:
$ ssocr rotate 2.08 crop 2157 1476 591 267 shear 20 -d4 -t98 -i1 -n2 -M10x10 ssocr_demo2.jpg
63.7
I plan to release ssocr
version 2.23.0 soon, perhaps tomorrow, with the two additional options -N
and -M
.
Awesome! Thanks again!
I have released ssocr
version 2.23.0 with -N
, -M
, and a -d
enhancement to allow a range of digits. That should address this issue.
Oooh the range of digits enhancement is great, too. Very handy.
If I understand correctly, -n applies only to detecting segments, and since 1 and - are detected separately, it does not apply to them.
Maybe it would be nice to have -n apply to detecting those digits as well, since they are also made of segments. For 1 it would be a minimum width, and for - a minimum height. This seems like a natural use of it.
It would help me avoid a lot of false detections of 1's. There are the noise-avoidance parameters (-i, remove_isolated, and keep_pixels_filter) but if -n applied it might be a pretty simple way to achieve the same?
Thanks for considering!