home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: Science
/
Science.zip
/
imdisp79.zip
/
IMAGUTIL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-17
|
22KB
|
687 lines
/*** IMDISP module IMAGUTIL.C
Special Purpose Device Independant Display Routines
Contains high level display routines such as interactive palette
adjustment, histogram display, and image profile drawing.
***/
#define __MSC
/* Changed 10/6/87 to read cursor keys without numlock - mdm */
/* * * * INCLUDE files * * * */
#include <math.h>
#include <stdio.h>
#include <conio.h>
#include "imdef.h"
#include "imdisp.h"
#include "dispio.h"
#include "disputil.h"
#include "display.h"
#include "keywutil.h"
#include "palutil.h"
#include "plot.h"
#include "refresh.h"
#include "textutil.h"
/* * * * External functions * * * */
/* * * * Function declarations * * * */
int DisplayHistogram (long *,int ,int ,int );
int Stretch (int ,int );
int Profile (void);
void DoNegative(void);
void DoWindow(void);
void DoRotate(void);
/* * * * Global Variables * * * */
long sin_table[MAXDISPNS+400];
long cos_table[MAXDISPNS+400];
int DisplayHistogram (long int * histbuf, int numbins, int minDN, int maxDN)
/*** DisplayHistogram diplays the passed histogram on the screen.
The third highest bin in the histogram is used to scale the
plot. The axes of the plot are labeled and annotated. The
number in each bin is indicated by the length of the line
drawn vertically from the axis.
Parameter Type Description
histbuf long int array the array of count values for each bin
numbins int the number of bins in the histogram
minDN int the minimum DN value in the histogram
maxDN int the maximum DN value in the histogram
***/
{
int top, bottom, left, right, height, pixperbin, width;
int i, DN, j, length, tic, tic_height=5;
int num_Xtics=16, num_Ytics=10, num_Xlabels=8, num_Ylabels=5;
long count, MaxCount;
char dispstring[16];
top = dispnl / 10;
bottom = dispnl - top;
left = dispns / 10;
right = dispns - (dispns / 100);
height = bottom - top;
pixperbin = (right - left) / numbins;
width = (numbins+1)*pixperbin;
right = left + width - 1; /* reset right edge */
MaxCount = max3arr( histbuf, numbins);
/* Draw the x axis (DN value) */
/* DrawLine (bottom, left, bottom, right, numDN-1); */
FrameBox( top, left, bottom, right, numDN-1, FALSE);
tic = (numbins / 16) * pixperbin;
tic_height = dispnl / 100;
/* Put in the tic marks */
for (i = 0; i <= num_Xtics; i++)
{
j = left + pixperbin + i*tic;
DrawLine (bottom, j, bottom+tic_height, j, numDN-1);
}
/* Put in the labels */
for (i = 0; i <= num_Xlabels; i++)
{
DN = i*0.125*((float)maxDN-minDN+1) + (float)minDN + 0.5;
if (DN < 0) DN--;
sprintf (dispstring, "%3d", DN);
j = left + (((numbins*i) / 8) + 1)*pixperbin - 15;
DrawText (dispstring, bottom+20, j, SmallChars, 0, numDN-1);
}
/* And write out the X-axis title */
DrawText ("DN value", bottom+40, left+(width / 2) - 75, TextHeight, 0, numDN-1);
/* Draw the y axis (Counts) */
/* DrawLine (bottom, left, top, left, numDN-1); */
for (i = 0; i <= num_Ytics; i++)
{
j = bottom - height*i/num_Ytics;
DrawLine (j, left, j, left-tic_height, numDN-1);
}
DrawText ("0", bottom-5, left-20, SmallChars, 0, numDN-1);
sprintf (dispstring, "%5ld", MaxCount);
DrawText (dispstring, bottom-height+5, left-60, SmallChars, 0, numDN-1);
DrawText ("Counts", bottom-(height / 2)+50, left-20, TextHeight, 90, numDN-1);
/* Draw the histogram lines */
j = left;
for (i = 0; i < numbins; i++)
{
j += pixperbin;
if (histbuf[i] > MaxCount)
length = height;
else
length = height*((float)histbuf[i]/(float)MaxCount) + 0.5;
if (Color_Hist)
DrawLine (bottom, j, bottom-length, j, i); /* color histo */
else
DrawLine (bottom, j, bottom-length, j, numDN-1);
}
}
int Stretch (int DNlow, int DNhigh)
/*** Stretch applies a linear gray scale ramp to the palette
starting with 0 at Dnlow and proceeding to 255 at DNhigh.
Parameter Type Description
DNlow int the starting DN value of the linear ramp
DNhigh int the ending DN value of the linear ramp
***/
/* int DNlow, DNhigh; */
{
Color CT[256];
/* struct Color CT[256]; */
float slope;
int i, shade;
if (DNhigh > numDN-1) DNhigh = numDN-1;
if (DNhigh < 0) DNhigh = numDN-1;
if (DNlow < 0) DNlow = 0;
if (DNlow > numDN-1) DNlow = 0;
slope = 256/ (float)(DNhigh - DNlow + 1);
for (i = 0; i < numDN; i++)
{
shade = slope*(i-DNlow) + 0.5;
if (shade < 0) shade = 0;
if (shade > 255) shade = 255;
CT[i].r = shade;
CT[i].g = shade;
CT[i].b = shade;
}
WritePalette (CT);
}
int Profile( void )
/*** Profile plots a profile of the pixel values between two points
on the screen. Cursor mode is used to select the two endpoints.
A line is drawn between the endpoints and a plot of DN value
versus distance along the line is made.
***/
{
int line1, samp1, line2, samp2;
int line, samp, distance, delline, delsamp;
int bottom, left, height, width, top, right;
int DN, minDN, maxDN;
int i, j, numpoints;
float t, scalefact;
char dispstring[64];
int DNvalues[MAXDISPNL+MAXDISPNS];
int Pixels[MAXDISPNL+MAXDISPNS];
unsigned char SavePatch[CURSORSIZE][CURSORSIZE];
MoveCursor (&line1, &samp1);
PlaceCursor (line1, samp1, numDN-1); CursorOn = 0;
for (i = 0; i < CURSORSIZE; i++)
for (j = 0; j < CURSORSIZE; j++)
SavePatch[i][j] = CursorPatch[i][j];
MoveCursor (&line2, &samp2);
for (i = 0; i < CURSORSIZE; i++)
for (j = 0; j < CURSORSIZE; j++)
CursorPatch[i][j] = SavePatch[i][j];
CursorOn = 1; CursorLine = line1; CursorSample = samp1;
RemoveCursor();
if (line1==line2 && samp1==samp2) return(0);
delline = line2 - line1; delsamp = samp2 - samp1;
distance = sqrt( (float)
( (long)delline*delline + (long)delsamp*delsamp ) ) + 0.5;
bottom = dispnl - 45; left = 60;
height = dispnl/3; width = dispns - 150;
top = bottom - height; right = left + width;
minDN = 255; maxDN = 0;
numpoints = distance;
if (numpoints > width / 2) numpoints = width / 2;
for (i = 0; i <= numpoints; i++)
{
t = (float)i/numpoints;
line = line1 + (int)(delline*t+0.5);
samp = samp1 + (int)(delsamp*t+0.5);
ReadPixel (line, samp, &DN);
if (DN < minDN) minDN = DN;
if (DN > maxDN) maxDN = DN;
DNvalues[i] = DN;
Pixels[i] = (int)(width*t+0.5) + left;
}
if (minDN == maxDN) scalefact = 0;
else scalefact = (float)height/(maxDN - minDN);
for (i = 0; i<= numpoints; i++)
DNvalues[i] = bottom - (int)( scalefact*(DNvalues[i] - minDN) + 0.5);
DrawLine (line1, samp1, line2, samp2, numDN-1);
/* Draw the x axis (Pixels) */
DrawLine (bottom, left, bottom, right, numDN-1);
DrawLine (bottom, right, bottom-5, right, numDN-1);
DrawText ("0", bottom+20, left, SmallChars, 0, numDN-1);
sprintf (dispstring, "%4d", distance);
DrawText (dispstring, bottom+20, right-30, SmallChars, 0, numDN-1);
DrawText ("Pixels", bottom+25, left+(width/2) - 70, TextHeight, 0, numDN-1);
/* Draw the y axis (DN value) */
DrawLine (bottom, left, top, left, numDN-1);
DrawLine (top, left, top, left+5, numDN-1);
sprintf (dispstring, "%3d", minDN);
DrawText (dispstring, bottom-5, left-40, SmallChars, 0, numDN-1);
sprintf (dispstring, "%3d", maxDN);
DrawText (dispstring, top+5, left-40, SmallChars, 0, numDN-1);
DrawText ("DN Value", bottom-(height / 2)+50, left-30, TextHeight, 90, numDN-1);
for (i = 0; i < numpoints; i++)
DrawLine (DNvalues[i], Pixels[i], DNvalues[i+1], Pixels[i+1], numDN-1);
}
void DoNegative(void)
{
int i;
unsigned char hold;
Color coltab[256];
/* struct Color coltab[256]; */
ReadPalette(coltab);
for (i = 1; i <= numDN/2; i++)
{ hold = coltab[numDN-i].r;
coltab[numDN-i].r = coltab[i-1].r;
coltab[i-1].r = hold;
hold = coltab[numDN-i].g;
coltab[numDN-i].g = coltab[i-1].g;
coltab[i-1].g = hold;
hold = coltab[numDN-i].b;
coltab[numDN-i].b = coltab[i-1].b;
coltab[i-1].b = hold;
}
WritePalette(coltab);
}
void DoWindow( void )
/* DoWindow - This routine will allow the user to select an area using the
cursor keys. A box is stretched (or rubberbanded) around
as the user moves the cursor around. The area is retained
to be either stored in a buffer or have filters applied to.
Written by Ron Baalke - 09/17/91
*/
{
int line1, samp1, line2, samp2;
int bottom, left, height, width, top, right;
char dummy[80];
unsigned char SavePatch[CURSORSIZE][CURSORSIZE];
int flag1, flag2;
int i,j;
GetKeywordString (CommandString, "CAN", "",dummy, &flag1);
if (flag1 != -1)
{
Image_Line = Image_Line1; /* Restore image coordinates */
Image_Sample = Image_Sample1; /* Ron Baalke - 09/18/91 */
Image_Height = Image_Height1;
Image_Length = Image_Length1;
Image_Zoom = Image_Zoom1;
Image_Subsample = Image_Subsample1;
return;
}
GetKeywordInteger (CommandString, "L1", 1, &line1, &flag1);
GetKeywordInteger (CommandString, "S1", 1, &samp1, &flag2);
if ((flag1 != -1) && (flag2 == -1))
{
if (line1 > dispnl) line1 = dispnl;
if (samp1 > dispns) samp1 = dispns;
}
else
{
MoveCursor (&line1, &samp1);
PlaceCursor (line1, samp1, numDN-1); CursorOn = 0;
for (i = 0; i < CURSORSIZE; i++)
for (j = 0; j < CURSORSIZE; j++)
SavePatch[i][j] = CursorPatch[i][j];
}
GetKeywordInteger (CommandString, "L2", 1, &line2, &flag1);
GetKeywordInteger (CommandString, "S2", 1, &samp2, &flag2);
if ((flag1 != -1) && (flag2 == -1))
{
if (line2 > dispnl) line2 = dispnl;
if (samp2 > dispns) samp2 = dispns;
}
else
{
RubberBand (line1, samp1, &line2, &samp2);
for (i = 0; i < CURSORSIZE; i++)
for (j = 0; j < CURSORSIZE; j++)
CursorPatch[i][j] = SavePatch[i][j];
CursorOn = 1; CursorLine = line1; CursorSample = samp1;
RemoveCursor();
}
if (line1==line2 || samp1==samp2) return;
if (line1 < line2)
{
top = line1;
bottom = line2;
}
else
{
top = line2;
bottom = line1;
}
if (samp1 < samp2)
{
left = samp1;
right = samp2;
}
else
{
left = samp2;
right = samp1;
}
FrameBox(top,left,bottom,right,numDN-1,TRUE);
/* save the dimensions of the box */
Image_Line = top+1;
Image_Sample = left+1;
Image_Height = bottom - top - 1;
Image_Length = right - left - 1;
Image_Zoom = 1;
Image_Subsample = 1;
}
/*************************************************************************/
/* DoRotate */
/* */
/* Written by Ron Baalke - 09/21/91 */
/* */
/* This routine will rotate an image between 0 to 360 degrees with an */
/* accuracy of 1 degree. Options are provided to clip the image in its */
/* original box, and to not fill in the dead areas around the image. */
/* The image is retrieved pixel-by-pixel from the refresh buffer, so the */
/* refresh buffer must be turned on for this routine to work */
/*************************************************************************/
void DoRotate(void)
{
int i,j,k;
int flag;
int clip_flag;
int nofill_flag;
int line;
int sample;
int height;
int length;
int angle;
int line_center;
int samp_center;
unsigned char buffer1[MAXDISPNS];
unsigned char buffer2[MAXDISPNS];
int save;
long cos_angle;
long sin_angle;
double dangle;
int line_diff;
int samp_diff;
long line_pixel;
long samp_pixel;
int skip;
int line_start;
int line_end;
int samp_start;
int samp_end;
int l1,s1,l2,s2,l3,s3,l4,s4;
int offset;
GetKeywordSubcommand (CommandString, "SCR", &flag);
GetKeywordSubcommand (CommandString, "CLI", &clip_flag);
GetKeywordSubcommand (CommandString, "NOF", &nofill_flag);
/* Rotate just the image or the entire screen */
if (flag == 1)
{
line = 1;
sample = 1;
height = dispnl;
length = dispns;
}
else
{
line = Image_Line;
sample = Image_Sample;
height = Image_Height;
length = Image_Length;
}
/* Error checking - angle must be between 0 to 360 degrees */
GetKeywordInteger (CommandString, "ROT", 0, &angle, &flag);
if (angle == 0 || angle == 360) return;
if (angle < 0 || angle > 360)
{
StatusLine(0,"Angle of rotation must be between 0 and 360");
return;
}
/* Refresh buffer must be turned on */
if (RefreshLines == 0)
{
StatusLine(0,"Refresh Buffer must be turned on to do rotations");
return;
}
/* calculate center, starting and ending points of the image */
line_center = line + height/2;
samp_center = sample + length/2;
line_start = line;
line_end = line+height-1;
samp_start = sample;
samp_end = sample+length-1;
/* special handle 180 degrees */
if (angle == 180)
{
/* loop through image line by line */
for (i=line; i<=line+height-1; i++)
{
if (kbhit()) /* Allow user to quit anytime */
{
getch();
return;
}
/* Read in each line */
GetLine(buffer1,i,sample,length);
/* Reverse the line */
for (j=0; j<length; j++)
buffer2[j] = buffer1[length-j-1];
/* Write the line out onto the screen, bottom up */
DisplayLine(buffer2,line+height+line-i-1,sample,length);
}
}
else /* angle != 180 */
{
/* Calculate the the sine and cosine of the angle and convert to long */
/* (The 10,000 factor will be divided out later) */
dangle = (((double) 3.14159 * (double) angle)/(double) 180.0);
cos_angle = (long) ((double)10000.0 * cos(dangle) + .5);
sin_angle = (long) ((double)10000.0 * sin(dangle) + .5);
/* calculate sin and cos tables (used to speed up the code) */
offset = (MAXDISPNS+400)/2;
for (i=0; i < MAXDISPNS+400; i++)
{
cos_table[i] = cos_angle * (long)(i-offset);
sin_table[i] = sin_angle * (long)(i-offset);
}
/* from here on out, all calculations are done with integer arithmetic */
/* If clipping is *not* selected, then rotate the four corners of the */
/* image, and calculate the new box size for the destination box */
if (clip_flag == -1)
{
/* initialize corner values */
l1 = line_start;
s1 = samp_start;
l2 = line_start;
s2 = samp_end;
l3 = line_end;
s3 = samp_start;
l4 = line_end;
s4 = samp_end;
/* rotate upper left corner point */
line_diff = l1 - line_center + offset;
samp_diff = s1 - samp_center + offset;
line_pixel = cos_table[line_diff] - sin_table[samp_diff];
samp_pixel = cos_table[samp_diff] + sin_table[line_diff];
line_pixel = (line_pixel + 5000L)/10000L + line_center;
samp_pixel = (samp_pixel + 5000L)/10000L + samp_center;
l1 = (int)line_pixel;
s1 = (int)samp_pixel;
/* rotate upper right corner point */
line_diff = l2 - line_center + offset;
samp_diff = s2 - samp_center + offset;
line_pixel = cos_table[line_diff] - sin_table[samp_diff];
samp_pixel = cos_table[samp_diff] + sin_table[line_diff];
line_pixel = (line_pixel + 5000L)/10000L + line_center;
samp_pixel = (samp_pixel + 5000L)/10000L + samp_center;
l2 = (int)line_pixel;
s2 = (int)samp_pixel;
/* rotate lower left corner point */
line_diff = l3 - line_center + offset;
samp_diff = s3 - samp_center + offset;
line_pixel = cos_table[line_diff] - sin_table[samp_diff];
samp_pixel = cos_table[samp_diff] + sin_table[line_diff];
line_pixel = (line_pixel + 5000L)/10000L + line_center;
samp_pixel = (samp_pixel + 5000L)/10000L + samp_center;
l3 = (int)line_pixel;
s3 = (int)samp_pixel;
/* rotate lower right corner point */
line_diff = l4 - line_center + offset;
samp_diff = s4 - samp_center + offset;
line_pixel = cos_table[line_diff] - sin_table[samp_diff];
samp_pixel = cos_table[samp_diff] + sin_table[line_diff];
line_pixel = (line_pixel + 5000L)/10000L + line_center;
samp_pixel = (samp_pixel + 5000L)/10000L + samp_center;
l4 = (int)line_pixel;
s4 = (int)samp_pixel;
/* determine new sample and line values based on the four corners */
/* that we just rotated */
line_start = l1;
if (line_start > l2) line_start = l2;
if (line_start > l3) line_start = l3;
if (line_start > l4) line_start = l4;
if (line_start < 1) line_start = 1;
line_end = l1;
if (line_end < l2) line_end = l2;
if (line_end < l3) line_end = l3;
if (line_end < l4) line_end = l4;
if (line_end > dispnl) line_end = dispnl;
samp_start = s1;
if (samp_start > s2) samp_start = s2;
if (samp_start > s3) samp_start = s3;
if (samp_start > s4) samp_start = s4;
if (samp_start < 1) samp_start = 1;
samp_end = s1;
if (samp_end < s2) samp_end = s2;
if (samp_end < s3) samp_end = s3;
if (samp_end < s4) samp_end = s4;
if (samp_end > dispns) samp_end = dispns;
}
/* Loop through line-by-line of the *destination* box */
for (i=line_start; i<=line_end; i++)
{
if (kbhit()) /* Allow user to quit anytime */
{
getch();
return;
}
line_diff = i - line_center + offset;
/* For each pixel in the destination box, we calculate where it */
/* resides in the refresh buffer, and display it on the screen */
k=0;
for (j=samp_start; j<=samp_end; j++)
{
samp_diff = j - samp_center + offset;
line_pixel = sin_table[samp_diff] + cos_table[line_diff];
samp_pixel = cos_table[samp_diff] - sin_table[line_diff];
line_pixel = line_pixel/10000L + line_center;
samp_pixel = samp_pixel/10000L + samp_center;
/* If the pixel in not in the source image box, we skip it */
skip = FALSE;
if ((line_pixel < line) ||
(line_pixel > line+height-1) ||
(samp_pixel < sample) ||
(samp_pixel > sample+length-1) ||
(samp_pixel == dispns))
skip = TRUE;
/* If not skipped, we grab the pixel from the refresh buffer */
if (!skip)
GetRefresh(&buffer1[k],(int)line_pixel,(int)samp_pixel,2);
/* For skipped pixels, check if NOFILL flag is set, and if */
/* not, then set the pixel to black */
else if (nofill_flag == -1)
buffer1[k] = 0;
else if (j < dispns)
GetRefresh(&buffer1[k],i,j,2);
k++;
}
DisplayLine(buffer1,i,samp_start,samp_end-samp_start+1);
}
/* Reset the coordinates of the new box to be the destination box */
Image_Line = line_start;
Image_Sample = samp_start;
Image_Height = line_end - line_start + 1;
Image_Length = samp_end - samp_start + 1;
}
/* save rotated image to the refresh buffer */
save = RefreshLines; /* temporarily disable refresh buffer to force the */
/* GetLine() routine to read from the screen */
RefreshLines = 0;
for (i=line_start; i<=line_end; i++)
{
GetLine(buffer1,i,samp_start,samp_end-samp_start+1);
PutRefresh(buffer1,i,samp_start,samp_end-samp_start+1);
}
RefreshLines = save; /* restore */
}