Departments


We Have Mail


Editor: CUJ

With regard to Dwayne Phillips' article histogram-based image segmentation last year (CUJ January 1992), I faced the problem of changing gray-scale video images to black-and-white. Here are a couple of tricks that worked quiet well:

The first trick does automatic, histogram thresholding — it finds the threshold value that separates "black" from "white":

The threshold value is the intensity value which is closest to the mid-point between these two values:

1) The average of all pixels equal or darker than it.

2) The average of all pixels brighter (higher) than it.

This trick finds a good threshold even when the histogram does not have distinct peaks. Note that the dark average (not the light average) includes the "weight" of the intensity value under consideration. Probably that was caused, not by deep thought, but by how the code was typed in.

Someday, I will have time to try recursing on this trick to do histogram-equalization. (That is, once you find the first threshold, find finer threshold values inside "white" and "black." And so on. Then, re-map the image according to the found thresholds.) It seems to me that whatever method you use to threshold an image ought to be usable in this way to get a best-case histogram-equalization mapping.

The second trick is a 3 X 3 filter that helps clean up the image before you threshold it. Filter/copy the image like this:

For each pixel, find the highest and lowest intensity values for the pixel and its eight neighbors. Make the new image's pixel equal to either the highest or lowest intensity value of the nine pixels, depending upon which is closest to the current, center pixel's intensity value. If the pixel's intensity value is exactly in the middle between the highest and lowest values, leave it be.

Examples:

34  44  56  Low value is 34, high is 56.
35  40  43  Change the 40 to a 34.
39  39  37

34  44  45  Low value is 34, high is 45.
35  40  43  Change the 40 to a 45.
39  39  37

34  44  46  Low value is 34, high is 46.
35  40  43  Leave the 40 alone.
39  39  37
With my images, this high-low filter, followed by an average filter, followed by this high-low filter again gave the best results. The 3 X 3 average filter was:

1  2  1
2  4  2
1  2  1
(That is, multiply the center pixel by 4, each of the pixels diagonal to it by 1, and each pixel beside it, above it, and below it by 2. Add the results together, divide by 16, and the result is the new center pixel value. This filter is fast on 80x86 CPUs.)

Applying first the high-low filtering, then histogram thresholding, did a good job of black-and-whiting video images of an LCD screen.

As a side note, I got pleasing histogram-smoothing results with a more complex method than the article used: Do exponential smoothing of the histogram from the bottom up and from the top down. Average the two resultant values. That is:

#define INTENSITY_LEVELS           256
int histogram[INTENSITY_LEVELS] = the values...
int up[INTENSITY_LEVELS];
int v, i;
for (v = i = 0; i < INTENSITY_LEVELS; ++i)
   up[i] = v = (histogram[i] + v) / 2;
for ( v = 0, i = INTENSITY_LEVELS; i----;) {
   v = (histogram[i] + v) / 2;
   histogram[i] = (up[i] + v) / 2;
}
This little riff worked out real well when done before histogram- equalizing one image to match the histogram of another.

Thank you,

B. Alex Robinson
22126 270th Ave SE
Maple Valley, WA 98038

Thanks for the tips. — pjp

Dear Sirs;

I enjoyed David Burki's "Date Conversions" article (CUJ, February 1993), plus his "A Brief History of the Calendar" sidebar.

For simple uses (in this century and in this country) the information is excellent. But danger lurks if you expand past that for astronomical, historical, and perhaps other types of databases. Here's some more information which any programmer working with dates must have:

1. According to English-usage columnist William Safire, B.C. goes after the year but A.D. (anno Domini, "in the year of the Lord") goes before. Thus, it's 46 B.C. and A.D. 46.

2. The Gregorian calendar was adopted at different times in different countries:

Date        Adopted by
1582        France, Italy, Spain, Portugal, Luxembourg
1583-4      most German Catholic states, Belgium, part of Switzerland,
            part of Netherlands
1587        Hungary
1699-1700   rest of Netherlands, Denmark, German Protestant states
1752        British Government incl. all colonies, incl. American colonies
1753        Sweden
1873        Japan
1875        Egypt
1912        China
1917        Turkey
1918        Russia
1923        Greece
Thus, many history books refer to dates during this transition period as either "old style" (O.S.) or "new style" (N.S.) depending on whether a country was following the older Julian or new Gregorian calendar at the time.

3. In 1752, the British Government decreed that the day after Sept. 2, 1752 would become Sept. 14. They also moved New Year's Day from Mar. 25 to Jan. 1 (under the old style, Mar. 24, 1700 had been followed by Mar. 25, 1701). "O.S." and "N.S." were used to distinguish between the Old Style dates and New Style dates. George Washington's birth date, which was Feb. 11, 1731, O.S., became Feb. 22, 1732, N.S.

4. In the Roman calendar (on which ours is based), March was the first month of the year. September gets its name from the Latin "septem" meaning "seven," because it is the seventh month when March is the first. This is why February gets that extra day — it's the last month of the year.

5. 46 B.C., incidentally, was the year 709 of Rome. The Roman calendar was based on the date April 21, 0753 B.C. when, according to legend, Rome was purportedly founded. I know 46 plus 709 doesn't equal 753; I haven't figured that one out yet.

And for human interest, it was in A.D. 730 that the Venerable Bede, an Anglo-Saxon monk, announced that the 365-1/4 day Julian year was 11 min., 14 sec. too long, creating a cumulative error of about one day every 128 years or 3 days every 400 years. Nothing was done about it until 1582.

Bibliography and References:

Scientific American, May 1982, pp. 150-151, "The Gregorian Calendar," by Gordon Moyer.

Astronomical Formulae for Calculators by Jean Meeus, 1982, Willmann-Bell, Inc.

The Discoverers by Daniel J. Boorstin, 1983, chapter 1, for an excellent historical discussion on calendars.

Practical Astronomy With Your Calculator by Peter Duffett-Smith, 3rd edition 1988, Cambridge University Press.

Calendrical Calculations by Edward M. Reingold and Nachum Dershowitz, 1989, University of Illinois at Urbana-Champaign.

The 1989 Information Please Almanac, pp. 549-550. (Or any of the various publishers' annual almanacs.)

Sincerely,

Peter Skye
550 North Brand Boulevard, 7th Floor
Glendale, CA 91203-1900

I find calendars to be a bottomless pit of detail. They are as Byzantine as politics — and rightly so. The whims of emperors often influence the shape of calendars far more than reason. Besides, how can you form a logical system in human terms that is based on solar, sidereal and lunar cycles that refuse to divide neatly into days? I thought I knew a lot of esoterica, but you taught me a few new twists.

As an aside, the UNIX cal program used to make a point of printing September 1752 "right," by American colonial standards. Give it a try. — pjp

Dear Mr Plauger,

C programmers frequently need to select an integer of a particular size; eight bit, 16 bit, 32 bit, etc. With the current ANSI/ISO standard, there is no way to do this in a portable manner. There also seems to be a potential problem in that some particular integer sizes may not be available at all. I am thinking particularly of what happens on large word-size machines.

Taking a 64-bit machine as an example, the current standard would permit, say, eight-bit chars64-bit shorts and 128-bit longs. How would I declare a 16 or 32 bit integer? Am I overlooking something? I would be interested to know.

I wonder if the ANSI C committee has considered the addition of a set of keywords for fixed-size integers. e.g.

int8, int16, int32, uint8, uintl6, uint32, etc
The standard could stipulate, for example, that a compiler should provide a minimum of all integer sizes up to, say, twice the machine size. This would give programmers precise control over all integer data sizes, a facility which I would find most useful, particularly when working with embedded systems.

Yours sincerely,

Ian Cargill
54 Windfield
Leatherhead
SURREY KT22
8UQ England
cargill @exnet.co.uk

Committee X3J11 did discuss proposals similar to yours and chose not to include them in the C Standard. You're right that any given implementation gives you a maximum of four different size integers. (Yes, int can differ from the other three sizes.) If a given implementation doesn't give you the sizes you need, you have to write some moderately ugly code to manipulate your data.

The Numerical C Extensions Group (NCEG or X3J11.1) has considered several proposals for specifying the exact size of integers, but I don't recall whether they've recommended any yet.—pjp

Dear Mr. Smith,

I read with interest your article "Debugging with Macro Wrappers" in The C Users Journal, October, 1992. I would be very glad if you could help me with the following question:

You recommend to enclose each statement sequence generated by a macro with

do { ... } while(0)
I cannot understand in what respect this is superior to using braces alone:

{ ... }
By the way: I believe that an ANSI-conforming way to create individual labels from a macro is the macro MAKE_LABEL below:

#define MAKELAB_(NR) _LAB_ ## NR
#define MAKE_LABEL MAKELAB(_LINE_)
The trick is to use an auxiliary macro MAKELAB_ which separates macro expansion for __LINE__. from token pasting in the correct way.

Sincerely yours,

Ronald Fischer
Haberl Strabe 12
#W 8000
Munchen 2
Germany
e-mail: 100042.2363@compuserve.com
CompuServe: [100042,2363]

Greetings:

Just a quick note to say I read the article "Debugging with Macro Wrappers" in the October, 1992 CUJ. Thanks much for some very helpful ideas. I also noted with interest your problems in smoothing out the macro for default. Being relatively new to C programming, your discussion of possible fixes went mostly over my head, but it occurred to me that the problem may be unnecessary in the first place. It may not be appropriate in this instance to be quite so elegant with the macro (as much as I admire an elegant programming solution). Would the following code work just as well for you? (Or for me, for that matter...)

#ifdef NDEBUG
       #define BUGCHECK break
#else
       #define BUGCHECK\
       .
       .
       //debug stuff
       .
       .
#endif
Rather than redefine default at all, and use the following in your source:

       default:
         BUGCHECK;
Perhaps there is some hideous, hidden reason why this won't work, but it looks reasonable, anyway. Plus it has the advantage (for my personal programming style at least) that the debug macro is visible in the source code, yet still adds no overhead when debugging is turned off.

Anyhow, thanks again for the helpful instruction — meanwhile, have fun.

Sincerely,

Bruce V. Edwards
P.O. Box 1922
Billings, MT 59103

Dear Mr. Smith,

Thanks very much for your article on wrappers.

Here is a label generator:

#define UniqueLabel GUL(__LINE__)
#define GUL(line) GULI(line)
#define GULI(line) L ## line
Bill McKeeman
Digital Equipment Corporation
110 Spit Brook Road
Nashua, New Hampshire 03062-2698

(Bill McKeeman is the notoriously competent writer of compilers and explainer of parsers whose books and articles you have doubtless read.—pjp)

Dear Mr. Smith,

I recently read your article entitled "An Essential String Function Library" in the January 1993 issue of The C Users Journal. I am a professional programmer and I am currently involved in a fairly large C programming effort which has many applications for your functions. My plan is to add your functions to a directory of reusable C software which is accessible by the entire project. I have enclosed a diskette in the hope that an electronic copy of your functions is available. Please return the diskette to the address below with a note listing any costs you incur in the process. I will be happy to reimburse you.

I also have a question about your use of va_start in str_vcat. va_start takes the last fixed parameter name as its second parameter. From the description given for str_vcat I understand that it has a minimum of two parameters. Used in this way it would set Dest to the null string. If this is correct, shouldn't the call to va_start be va_start(VarArgList, Strl)?

Thank you for your interesting and insightful article.

Sincerely,

Elizabeth D. Bennington
12501 Carter Avenue
Fredericksburg, VA 22407

William Smith replies to all:

Thanks for the interest and insightful ideas!

Dear Mr. Plauger:

I would like to propose a new financial vehicle for software production called the Premium Bond. This Bond would have a price range from $25 to $100. Your subscribers and staff would recommend software that they would like to have developed, and the Journal would publish a listing together with the Bond price.

For example, I would like to have a Borland C++ genetic algorithm (GA) so I would purchase a %50 GA Bond. Let us say the 2,000 subscribers purchased this bond, then thefund would have $100 for software development. Based on a reasonable proposal, a programmer or team of programmers would be given the software contract.

By purchasing the software, the bond subscribers would have the right to use the routines for their own purpose without worrying about copyright infringement. On the CompuServe network a news release from Borland indicated that they sold at least 800,000 copies for the C++ Framework software. Immediately you can see that Premium Bond funds could reasch upwards of $80,000,000 which wowuld attract the best C language programmers in the business.

Taiwan and Singapore are now in the process of constructing entire cities devoted to developing new software using advanced desktop computers networked to supercomputers. The Premium Bond would help us remain competitive in the years to come by provinding the funds needed to develop world calss software.

Cordially yours,

John St. Clair
52 Kings Couurt, 4A
San Juan, Puerto Ricoo 00911

You have done a marvelous job of describing a financial market for software. Several stock exchanges do this sort of thing at a coarser level by how they value various software companies. To do so at the level of detail you desire requires two new players, administrators and bond traders. I assure you that they will get their share of the take first. It would be interesting to see whether programmers could learn to interact on a regular basis with folks of either stripe. — pjp.