TRANSFORMATION OF DIGITAL IMAGES

Abstract: In general, the invention consists of a means for staining a sample with a fluorescent dye, a means for producing a darkfield image of the fluorescent stained sample, and a means of transforming an image of a sample stained with one or more darkfield dyes into an image stained with one or more brightfield dyes for examination on a computer monitor. The process includes applying a digital lookup table or other computational means in order to convert the darkfield data to brightfield forms, and a means of displaying said transformed information. Preferably, the imaging means is a block face microscope, and the means for transforming the images is a digital computer.

Description: TRANSFORMATION OF DIGITAL IMAGES Background of the Invention The invention relates to the field of histology. In present day practice, the preparation of organic tissue samples and other material for transmission microscopy, both visible light and electron microscopy, is normally carried out by subjecting the sample to a series of chemical treatments culminating in the production of a solid block in which the sample is embedded. After the block is produced, thin sections of the sample (with the surrounding embedding material) are cut from the block and transferred to glass slides or other support. The embedding material may then be chemically removed and the tissue section stained with a variety of colored or fluorescent dyes, immunohistochemical stains, or subjected to in situ hybridization prior to examination. In conventional histopathology, the most common brightfield stain applied to clinically important tissue sections is the hematoxylin and eosin (H&E) formulation. This method results in staining of nucleic acids and other so-called "basophilic" substances in the tissue section with a blue-purple coloration, and proteins and other "acidophilic" or "eosinophilic" tissue components with a pink coloration. This stain is used world-wide as a general screening method for the examination of all tissue components, to be followed in certain cases by special stains that have affinities for specific tissue elements such as microorganisms or nerve processes, and therefore enhance their appearance on stained tissue sections. Methods have been introduced for en bloc staining, wherein the entire sample is stained by immersion before being subjected to infiltration and embedment. Sections are then cut from the block for transmission microscopy, or the cut face of the block itself is imaged in a process called block face microscopy or surface imaging microscopy. In the latter method, including that implemented in U.S. Patent No. 4,960,330, a sample that has been stained en bloc with either conjugated or unconjugated fluorescent dyes is subsequently infiltrated by and embedded in a medium, commonly a plastic polymer, that is heavily opacified or otherwise treated to allow for the suppression of images of tissue originating from more than a small number of microns deep within the block. This results in the production of a thin, "virtual section" closely resembling a conventional glass-slide mounted tissue section. Block face microscopy is advantageous over standard brightfield microscopy in that block face methods allow for the generation of high-quality microscopy images of biological tissue and other materials without the need to manufacture glass histology slides. The elimination of this requirement permits full automation of the histopathologic process, reducing incremental costs for each additional section produced, and consequently allowing for much greater amounts of information to be collected from each sample. In block face microscopy, the digital virtual section as captured unmodified from the block face is a dark field image resulting from the colored emissions from the fluorescence-stained sample appearing against a black background representing the opacified polymer in which the sample is infiltrated and embedded. In contrast, conventional optical transmission microscopy, including that practiced in most surgical pathology laboratories and other medically-related microscopy-based diagnostic facilities, produces a brightfield image because thin slices of tissue and other material are stained with standard non-fluorescent dyes and are then trans-illuminated with a white or near-white light source, resulting in a background that is brighter, rather than darker than the tissue image. In order to optimize block face microscopy images for clinical diagnosis and other purposes, it is preferable that the raw darkfield images captured from the face of the block be transformed and displayed as the more familiar images encountered in brightfield microscopy. Summary of the Invention In general, the invention consists of a means for staining a sample with a fluorescent dye, a means for producing a darkfield image of this fluorescent stained sample, and a means of transforming the darkfield images into bright field images for examination on a computer monitor. The process includes applying a digital lookup table or other computational means in order to convert the darkfield data to brightfield forms, and a means of displaying the transformed information. Preferably, the imaging means is a block face microscope, and the means for transforming the images is a digital computer. Accordingly, in a first aspect, the invention features an image production method that includes: (a) staining a sample with a fluorescent dye; (b) producing a first image of the resultant fluorescent-dyed sample; and (c) using a digital processor to convert the first image to a second image that mimics an image of the sample stained with a non-fluorescent dye. In a preferred embodiment, the converting of the first image to the second image includes applying a lookup table to the first image. In preferred embodiments, the modifying includes inverting the lookup table, or adjusting the color ranges of either the first image or the second image to mimic the color ranges of the sample stained with a non-fluorescent dye. The sample can be stained with one dye or with two or more dyes. A preferred sample is a biological sample. The invention also features an image production method that includes: (a) staining a sample with a first and a second fluorescent dye; (b) producing a first image of the sample stained with the first dye and a second image of the sample stained with the second dye; and (c) using a digital processor to convert the first and second images to a third image that mimics an image of the sample stained with hematoxylin and eosin. The invention features an image production method that includes: (a) staining a sample with a fluorescent dye; (b) producing a first image of the sample stained with the dye and a second image of the sample stained with the dye; and (c) using a digital processor to convert the first and second images to a third image that mimics an image of the sample stained with hematoxylin and eosin. The invention also features an image production method that includes: (a) staining a sample with the plurality of fluorescent dyes; (b) producing a first image of one of the dyes in the sample; and (c) using a digital processor to convert the first image to a second image that mimics an image of the sample stained with one non-fluorescent dye. In another aspect, the invention features an image production method that includes: (a) staining the sample with the plurality of fluorescent dyes; (b) producing a first image that mimics the sample stained with a subset of fluorescent dyes; and (c) using a digital processor to convert the first image to a second image that mimics an image of the sample stained with one or more non-fluorescent dyes. Preferably, the first and second images of the invention are produced using an apparatus that includes a block-face microscope. The dye used in the invention can include a metachromatic dye (e.g., acridine orange). By "conjugated" dye is meant a dye that is bound to a molecule having aspecificity for tissue elements. Exemplary conjugated dyes include, without limitation, fluorescently-coupled antibodies and fluoresc dna probes. By "unconjugated" dye is meant a dye that is inherently fluorescent. By "infiltration" is meant treating the tissue with a liquid or series of liquids which penetrate throughout the tissue to the molecular level and are then transformed into a solid in order to render the sample rigid. By "embedding" or "embedment" is meant positioning the infiltrated tissue in a mold and surrounding it with a substance (usually the same as the infiltrating substance) which is then hardened to form an encasing block. The embedding substance thus serves to provide rigid support and to facilitate the cutting process. By "sectioning" is meant cutting from the block thin slices which may then be mounted on glass slides or other support. By "staining" is meant treating a material with a colored or fluorescent substance that associates with the material on the molecular level. "Fluorescence" or "darkfield" staining is accomplished using unconjugated dyes (i.e., dyes that are naturally fluorescent when excited with light of the proper wavelength) or conjugated dyes (i.e., molecules that bind to the sample and that are attached, either directly or indirectly, to a fluorochrome). Examples of conjugated dyes include without limitation: (i) a primary antibody that binds to an antigen and a secondary antibody, containing a fluorochrome, that binds to the primary antibody; and (ii) a molecule that has, covalently bound to it, a fluorochrome. Fluorescence staining results in images that have a black background, while "standard" or "brightfield" staining is accomplished using dyes that are usually non-fluorescent and results in images with a bright, or white background. It is understood that the same dye could be useful for both fluorescence and standard microscopy. "Metachromatic" dyes constitute a subset of histochemical stains, many of which are fluorescent. Like most fluorochrome s, these compounds absorb light of a specific wavelength and re-emit it at a longer wavelength or wavelengths. The spectral properties of metachromatic dyes are strongly influenced by their proximity to target molecules, such that their emission wavelength is altered. Thus, these dyes change colors when they combine with certain types of materials. In some cases, the metachromatic dye may emit light only when bound to its target, and is otherwise not visible. An exemplary metachromatic dye is acridine orange. Other metachromatic dyes are known to those skilled in the art and include, without limitation, those listed in Conn's Biological Stains, Williams & Wilkens 9th Ed. 1977 (hereby incorporated by reference), and those available from Molecular Probes, Inc. (Eugene, OR). Most of the latter dyes are the subject of issued U.S. patents, all of which are hereby incorporated by reference. The Molecular Probes metachromatic dyes, which tend to label proteins, are catalogued as falling into the following three categories: bezoxadiazole derivatives, napthalene derivatives, and pyrene derivatives. By this method, image data on biological tissue and other materials may be generated efficiently by means of block face microscopy, and displayed in the most useful and familiar form as bright field images. Other features and advantages of the invention will be apparent from the following description of the preferred embodiments thereof, and from the claims. Brief Description of the Drawing The figure is a schematic illustration of the method of the invention, including applying a lookup table to a first image to yield a second image, yielding modified color Detailed Description of the Invention We have discovered a method for imaging a sample, such as a tissue sample, with one or more darkfield dyes and transforming the image to a second image that mimics an image of a sample stained with one or more brightfield dyes. The method of transforming a first image to a second image can involveapplying a lookup table to the first image. Lookup tables The transformation of a first image to a desired second image generally uses a collection of conversion values referred to as a lookup table. A lookup table consists of a list of color value relationships describing a one- to-one transform and may be generally computational according to certain criteria set by the user of the imaging system. Means for transforming digital images include general methods such as transfer functions that apply a mathematical formula to each data element. Examples include image color inversion transformations that may act by subtracting all data elements from some constant value. Alternatively, each data element in the image may be altered according to some higher-order computed result based upon analyses of patterns or other features in the image. For example, the value of every data element in some region of interest within an image may be summated, and this total value used to determine the general color of the region as it is displayed. Methods involving such higher level computations to determine a stain simulation are referred to in the invention as "computed stains." In general, a lookup table, such as an RGB (red, green, and blue) lookup table, is applied to each channel (e.g., the red channel, the green channel, etc.) of the darkfield image. In the course of converting the image from a darkfield image to a brightfield image, each source darkfield sample value (e.g., each pixel) is used as an index to reference the lookup table in order to ascertain the corresponding value for the brightfield image. The colors obtained for each channel are then combined to create the RGB brightfield image. Methods for color mapping and described, for example, in J.C. Russ (1995) The image processing handbook. 2nd edition CRC Press, Ann Arbor, MI, hereby incorporated by reference. Additive colorspace conversion In one example, a table of RGB colors is created with one entry for each possible darkfield value. For example, if the source (i.e., the darkfield image) has a range from 0 to 255 (wherein 0 is black and 255 is white), a table of 256 entries is created. Each entry in the table is filled with a color that can be obtained as follows: H=target color hue S=target color saturation B=target color brightness * I/max_sample_value (e.g., 8-bit = 255) where I is the index of the current lookup table value being calculated, and ranges from 0 to max_sample_value (e.g., 255). The resulting HSB color is converted to RGB colorspace and is inserted into the lookup table at position I. The result is that each lookup table entry is a brightness-scaled version of the target brightfield image color. The colors in the table span a range from black, ascending in brightness up to the last entry, which is the unmodified target image color. For example, if the target color were primary red, then the lookup table would start at black, gradually increase from darker reds to brighter reds, to the last entry, which would be primary red. For each set of source channels, the RGB colors obtained from the lookup table are added (e.g., red to red, green to green, blue to blue) to obtain one RGB color. The values are limited so that the max_sample_value (e.g., 255 for 8-bit) is not exceeded. A brightening value is then added to each RGB value. This value is obtained by taking the "darkness" of the original, darkfield image and converting it as follows: max_sample_value - maximum(source channel 1, source channel 2, ...) The largest of the source sample values is subtracted from the max_sample_value to obtain a darkness level. The darkness level is added to each component of the new RGB color to brighten it by that amount. The result is that source sample values that were very dark become very bright. Subtractive colorspace conversion In a second method for converting a darkfield image to one resembling a brightfield image, a lookup table of RGB colors is created as described above, except that each entry in the table is filled with a color that can be obtained as follows: H=target color hue S=target color saturation * I/max_sample_value (e.g., 8-bit = 255) B=target color brightness The resulting HSB color is converted to RGB colorspace and is inserted into the lookup table at position I. The result is that each lookup table entry is a saturation-scaled version of the target brightfield image color. The colors in the table span a range from white, ascending in saturation up to the last entry, which is the unmodified target image color. For example, if the target color were primary red, the lookup table would start at white, increasing from lighter reds (pinks) to more saturated reds until the last entry, primary red. Thus, using the foregoing method, each source channel is converted to an RGB color. These colors are blended as follows. The RGB colors are converted to CMY (cyan, magenta, and yellow) colors. CMY is subtractive color space. The CMY colors are added (e.g., the cyan values from each source channel are added to produce a single cyan value, the magenta values from each source channel are added to produce a single magenta value, etc.). As described herein, it is desirable to restrict the values to the maximum allowed (i.e., the max_sample_value). Following summation, the resulting CMY color is reconverted to RGB colorspace. In the case of the conversion of a darkfield image stained with acridine orange to a brightfield image stained with H&E, the increase is from black to the target color (in the case of additive colorspace) or white to the target color (in the case of subtractive colorspace) is linear. Those skilled in the art will recognize that other lookup tables, including non-linear or even discontinuous lookup tables, are also useful in the invention. Staining with darkfield dyes One method for computationally generating an image of a sample stained with a brightfield dye or combination of dyes (e.g., H&E) is to stain the sample with a mixture of fluorochrome stains that differentially bind to various tissue structures or, alternatively, with a single fluorescent stain that produces more than one color when applied to a sample (i.e., a metachromatic dye). The image conversion methods described herein allow for conversion of the darkfield image of a sample stained with one or more darkfield dyes to mimic an image of the sample stained with one or more brightfield dyes. In one example, a sample containing fungal organisms is stained with a combination of fluorescent dyes, one of which displays higher affinity for the fungal organisms and another of which displays higher affinity for components of the tissues. A darkfield image of the sample stained with these dyes would reveal fungal organisms labeled with a distinctive color relative to the tissue. Upon conversion to a brightfield image (using standard methods such as those described herein), the differential color properties of the original image are transformed to a brightfield image of tissue containing fungal organisms. In a second example, a darkfield image of a sample containing fungal organisms, which has been stained with a single, monochromatic dye, is transformed to yield a polychromatic brightfield image by assigning different brightfield colors to various grayscale intensity values in the original darkfield image, for example, if the fungal organisms display a greater affinity for the monochromatic dye than does the tissue, the difference in intensity can be used to yield one set of brightfield colors for the brightly stained sample (i.e., the fungal organisms) and a second set for the dimly stained sample (i.e., the tissue). Other distinctive properties, such as size, can also be used to computationally assign brightfield colors. Encoding multiple stains in a single sample A sample can be stained with multiple dyes, while only one or a subset of these dyes is imaged. At another time, the other dyes from the same sample can be imaged using different filter cubes or excitation methods. Thus, one sample can contain many more dyes than are imaged at one time. Dyes that are imaged at the same time can be distinguished from each other using filter cubes that restrict the wavelengths of emitted light that reaches the detector. Alternatively, individual dyes can be distinguished using spectral analysis or other higher order analysis. Such methods for imaging tissue are described in Levenson, R.M. and Farkas, D.L. (1997) Proc. SPIE, 2983: 123-135; Levenson, R.M. and Young, D.A. (1991) In: M.J. Dunn (Editor), Proc. International Meeting on Two-Dimensional Electrophoresis. Dept. of Cardiothoracic Surgery, National Heart and Lung Inst. (UK), London, UK; and Levenson, R.M., Brinckmann, U.G., Androphy, E., Schiller, J., Turek, L., Chin, M., Broker, T.R., Chow, L.T. and Young, D.A. (1987) In: B.M. Steinberg, J.L. Brandsma and L.B. Taichman (Editors), Cancer Cells V. Papillomaviruses. Cold Spring Harbor Press, New York, pp. 137-144, all of which are hereby incorporated by reference. The following examples are to illustrate the invention. They are not meant to limit the invention in any way. Examples Example I: Single Dye Method for H&E The metachromatic dye acridine orange is a fluorescent dye in which the color of the fluorescence produced upon staining tissue and other material is dependent on the chemical composition of the tissue element to which it is bound. For example, nucleic acids emit a yellow color upon staining with acridine orange, while cytoplasmic proteins simultaneously emit a green color when so stained. Thus, the color differentiation of tissue elements resulting from staining of tissue and other materials with acridine orange is similar to that seen with H&E, except that different specific colors are produced, and in addition, acridine orange, being a fluorescent stain, produces a darkfield, rather than a brightfield, image. A specific algorithm for making display data that appears as a brightfield H&E stain from a fluorescent sample using initially stained using acridine orange and captured with a digital camera is as follows. The input image is digitized by the camera, yielding pixels which, are black or only have red and green values. The output pixels represent an RGB image that will appear as a brightfield image stained with Hematoxylin and Eosin. Let: Sr,Sg = the source pixel values for red and green Dr, Dg, Db = the destination pixel values for red green and blue Pmax = the maximum value of a pixel (i.e. 8-bit = 2 Λ 8 = 256, 10-bit = 2 Λ 10 = 1024, etc.) Hr, Hg, Hb = the RGB indices of a Hematoxylin brightfield color Er, Eg, Eb = the RGB indices of an Eosin brightfield color Dr = Pmax - max(Sr, Sg) + (Sr/Pmax)*Hr + (Sg/Pmax)*Er Dg = Pmax - max(Sr, Sg) + (Sr/Pmax)/Hg + (Sg/Pmax)*Eg Db = Pmax - max(Sr, Sg) + (Sr/Pmax)/Hb + (Sg/Pmax)*Eb The invention thus makes possible the conversion of images of acridine orange stained tissues into images resembling H&E stained tissues by means of applying a color lookup table or other means of color transformation to the images of acridine orange stained tissue. Those skilled in the art of H&E staining will recognize that there is variability in the hue and saturation of tissue stained with each component due to variations in the production or storage of the staining solution. Thus, more than one look-up table can be used to convert a darkfield image of a sample stained with acridine orange to mimic a brightfield image stained with H&E. Appendix A lists computer code (in the computer language C) for a program that generates lookup tables for specified target-stained colors suitable for transforming a darkfield image of a sample stained with acridine orange to a brightfield image of the sample stained with H&E. Example II: Multiple Dye Method for H&E Fluorescent stain mixtures that differentially color basophilic and acidophilic substances in tissue may be substituted for acridine orange, and suitable lookup tables or other means created to transform the resulting darkfield images into those which resemble standard brightfield H&E images. One alternative formulation is a combination of propidium iodide (to stain nucleic acids) and eosin Y (to stain proteins). In one example, a biopsy of cancerous tissue is treated with propidium iodide, a yellow fluorescent stain that binds in a quantitative manner to nucleic acids, and is commonly used for the quantitation of DNA in flow cytometric studies of tumor cell nucleic acid content. The tissue is also stained with eosin Y to color green the non-nuclear components of the tissue. According to the invention, a darkfield image captured from this tissue sample is transformed into a brightfield image in which the background color appears white, the non-nuclear portion of the tissue appears pink, and the nuclei appear blue. Alternatively, the fluorescence intensity of each nucleus is quantitatively measured to approximate the DNA content of the nucleus, which quantity relates by a color lookup table or other means to the color to be applied to the brightfield image of each nucleus, such that each nucleus will display a different color according to the total amount of DNA contained therein, thus resulting in a "computed stain" that relates to DNA content. Example III: Method for producing a polychromatic image from a monochromatic dye In a third example, by use of the invention, an image of a monochromatic stain is converted to a polychromatic image resembling an image of a sample stained with a polychromatic stain or multiple monochromatic stains. One example is the application of the blue- white stain Fluorescence Brightener 28 to tissue samples containing fungal organisms. Fluorescence Brightener 28 strongly binds to fungal bodies and makes them appear much more prominent than other structures in darkfield images, such as the cells of the infected organism. Hence, in an image with pixels representing 256 shades of gray (in which a pixel value of 0 is black, and a pixel value of 255 is white), the pixels representing the fungal bodies have high pixel values. In one example, the fungal bodies have a pixel value greater than X, while the non-fungal structures each have a pixel value less than X. A color lookup table is created to transform the more brightly staining fungal bodies (i.e, all pixels greater than X) into a first brightfield color such as dark purple- grey; the remaining structures of the tissue (i.e., all pixels between X and 0) are transformed into a second brightfield color such as pale green. Similarly, the black background (i.e., all pixels with values of 0) is made to appear white, thus producing a brightfield appearance. This coloration combination results in an image closely resembling the Grocott methenamine-silver stain, which is commonly employed in surgical pathology laboratories to stain fungus in tissue sections. Other Embodiments While this invention has been particularly shown and described with references to preferred embodiments thereof, it will be understood by those skilled in the art that various changes in form and details may be made therein without departing from the spirit and scope of the invention as defined by the appended claims. Those skilled in the art will recognize or be able to ascertain using no more than routine experimentation, many equivalents to the specific embodiments of the invention described specifically herein. Such equivalents are intended to be encompassed in the scope of the claims. What is claimed is: APPENDIX static chax apsstaι-ι_id( ] = "Sid: apsatain.cpp. 1.7 1999/04/29 21:35:44 beπn Exp $ ■ ((include vmdows.h> .include <atdιo.h> Iinclude <a ri-.g.h.> tincludβ 'cellvuβ.h* ♦include -color.h" ♦include "apsscβJ.n.. " ♦include 'apsini.h" inline BYTE Invertcolor (BYTE mono) { return 255 - mono; ) inline APSCLR Invertedor (APSCLR cl) ( return RGBCLR! InvercColαr (RGBRED (cl) ) , InvertColor (RGBGREEN (cl) ) , InvertColor (RGBBLUE(cl) ) ) ,- ) inline APSCLR RαtateColor (APSCLR cl) { return RGBCL (RGBBLUE (cl) ,RGBRED(cl) , RGBGREEN(cl) ) ; ) inline BYTE MaxC roma (APSCLR c) { return MA (MA (RGBRED (c) , GBGREEN (C) ) , RGBBLUE (c) ) ; ) inline APSCLR AddColo s (APSCLR cl,BYTE mono) ( return RGBCLR ( MIN(RGBRED(cl)*aioi.o,255, , MIN(RGBGREEN (cD+roono, 255) , MIN(RGBBLUE(cl) ♦mono, 255) ) ; inline APSCLR AddColora (APSCLR cl.APSCLR c2) { return RGBCL ( MINI GBRED (Cl) +RGBRED (c ) ,255) , MIN (RGBGREE (cl) +RGBGREEN (c2 ! , 255 ) , MIN(RGBBL0E(cl)+RGBBLUE(c2) ,255)1 ; ) inline APSCLR AddColors (APSCLR cl, APSCLR c2,BYTE mono) ( return RGBCLR ( MIN(RGBRED(cl)+RGBRED(c2)+moao.255) . MIN(RGBGREEN (cl) +RGBGREEN (c2 ) +mono , 2S5 ) , MIN(RGBBLUE.cl)+RGBBLUB(c2)ι-m-.no,255) ) ; ) inline APSCLR AddColors (APSCLR cl,APSCLR c2,APSCLR c3) { return RGBCLRI MIN(RGBRED(cl)+RGBRED(e2)+RGBRED(c3) ,255) , MIN(RGBGREEN (Cl) +RGBGREEN <c2 ) +RGBGRE£N(c3 ) ,255) . MIN (RGBBLUE ( cl ) +RGBBLUE ( c2 ) +RCBBLUE ( c3 ) , 2S5 ) ) ; ) inline APSCLR AddColors (APSCLR cl,APSCLR c2,APSCLR c3,APSCLR c4) ( return RGBCLR! MIN(RGBRED (Cl) +RGBRED (c2 ) +W-BRET. (c3 ) +RGBRED (c4) ,255) , MIN (RGBGREEN ( cl ) +RGRCREEN (e2 ) J-RGBGREEN (c3 ) +RGBGREEN ( i ) , 255 ) , MIN (RGBBLUE (cl)+RGBBLUE(cP)+RGBBLUH(c3)+RGBBLU1ϊ(c4) ,255) ) ; ) /• overlaycolors does subtractive colorspace color adding conceptually rgbl->cmyl rgb2-^ffiy2. c..yl +cmy2 ->cmy3 . CTiy3 ->rgnout rgb -> cmy 13 simply c = 1.0 - r , ra = 1.0 - g , y = 1 .0 - b cmy back to rgb is . of course : r = 1 . 0 - c , g = 1 . 0 - m, b = 1 . 0 - y so f or -acn channel c£ rgbl k rgb2 to do a subtracts v* colorβpace add we are αomg the following . out ■ 1. 0 - ( ( 1.0 - ml) + (1.0 - m2 ) ) doing the algebra we get: out » 1.0 - (2.0 - lnl - ιn2) out « 1.0 - 2.0 + ml + ιn2 out = inl + αn2 - 1.0 so going to 0 - 255 chrominance space from normalized cnrominance space and adding bounds checking, w* get: out = MAX(0,inl+ιn2-255) additional channels, of courae, work the same way, but with the algebra appropriate to the number of colors being added. for 3 colors we end up with: out » ml + in2 - m3 - 2.0 out - MAX(0,l»l+ιn2+ n3-510) for 4 colorβ we have: out ■ isl + ιιv2 * In3 + ιn4 - 3.0 out = MAX(0,ιnl+ιn2+in3+ιπ4-765) */ mime BYTE SubtractiveAdd (BYTE cl.SYTE c2) ( return MAX (cl+c2-255 , 0) ; } inline EYTE SubtractiveAdd (BYTE cl.BYTE C2.BYTE c3) { return MAX(cl+c2+c3-S10, 0) ; ) inline BYr SubtractiveAd (BYTE cl.BYTE C2.BYTE c3,BYTE c4) { return MAX(cl+c2+c3+c4-765, 0) j ) inline APSCLR Ove ltvColore (APSCLR cl,APSCLR o2) ( //this is what we are doing conceptually //return InvertColor (AddColors (InvertColo (cl) , InvertColor (c2) ) ) ; //this is the optlirazed algebraic distillation return RGBCLR( SubtractiveAdd!RGBRED (cl) , RGBRED(c2) ) , Subtract-. Λ.dd (RGBGREEN (Cl) , RGBGREEN!c2) ) , SubtractiveAdd (RGBBLUE (Cl) ,RGBBLUE(c2) ) ) ; ) inline APSCLR OverlayColore (APSCLR Cl,APSCLR c2,APSCLR c3 ) ( //this is what we are doing conceptually //return InvertColor (AddColors (InvertColor (cl) . Inverr.Co. o (c2) , InvertColor! c3 ) ) ) ; //this s the optimized algebraic distillation return RGBCLR( SubtractiveAdd (RGBRED(cl) ,RGBRED(c2) ,RGRRED(c3) ) , SubtractiveAdd (RGBGREEN (cl) ,RGBGREEN(c2) , RGBGREE (c3 ) ) , Subtrac iVβAdd ( GBBLUE (cl) .RGBBLUE (c2) , RGBBLUE (c3) ) ) ; } (c3 ) , InvertColor <c4) ) J //this is the optimised algebraic distillation return RGBCL ( SubtrβCtiVeAddtRGBRED(cl) .RSBRFD(c2) ,RGBRΞD(cJ) ,RGBRED(c4) ) , SubtractiveAdd!RGBGREE (cl) , RGBGREEN (c2 ) .RGBGREEN (c3 ) .RGBGREE (c4) ) , SubtractiveAdd!RGBBLUE(cl) .RGBBLUE (C2) ,RGBBLUE!c3) .RGBBLUE(c4) ) ) ; ) inline APSCLR HSV2APS (HSVCOLOR -hsv) ( DRCBCOLOa. drgbi HSV2DRGB (llS ,&dryJ ) ; return RGBCL ((BYTE) (2S5 0'drgb.r) . (BYTE) (755. O'drpb.g) , (BYTE) (255.0 » drgb.b) ) / - 1! class CHSVCOLOR { public: HSVCOLOR m_Color; inline CHSVCOLO (double h, ouble s, ouble v) { _Color.h ■ h; m_Color.s - s m^Color.v « v; ) inline operator HSVCOLO (void) ( return ro_Color; ) ); CApsLUT : :CApsLUT ( ) ( memset (this, 0, sizeof ('this) ) ; CApsLUT: : -CApsLUT ( ) ( ) void CApsLUT: :Build (HSVCOLOR firstColσr, HSVCOLOR lastColo , iπt iratloje/'-O*/, int Iascldx/*«2S5*/) ( double run = (double) (lastldx - firstldx) ; double dh = lastColor.h - firstColor.h; double as - lastColor. s - firstCclor.s; double v « lastColor.v - firstColor.vs int i - lastldx - 1; APSCLR 'entries - Entries!); HSVCOLOR curColor; double fctr; entries (firstldx) = HSV2APS(fcfirstcolor) ; entries (lastldx) = HSV2APS UlastColor) ; do ( fctr c (double) i/run; curColor.h = firstColor.h + fctr*dh,; cuxColor.s » firstColor.s + fetr'Oa; curColor. = tirstColor.v + fctr*dv; entriesti) - HSV2APS (acurcoior) ; i~; ) while <i>firs tldx) ; J CApsStain: : CApsStain () ( memset (this, O.aizeof ('this) ) ; ) C ApeStain::CApsstAin (const char * name, HSVCOLOR defColor.inc hueMin, int hueMax) ( memse ( h s, O.εizeof ('this) ) ; Name (name) ; DβfnultColor (defColor) ; UserDefaultColor (defColor) ; HueMi (hueMin) ; HueMax (hueMax) ; CurrentColor (def Color) ; ) CApsStain: :CApβStain (const char • name , HSVCOLOR defColor.inc hueMin.ir.t hueMa . HSVCOLOR xOverColor. in t xOverVal , BOOL xoverFade) ( memset Ithis.O.sizeo Cthis) ) ; Name (name) i De ultcolor (defColor) ; UserDefaultColor (de Color) ; HueMin(hueMin) i HueMax (hueMax) CurrentColo (defColor) ι XOverColor (xOverColor) ; xoverval (xθverVa.1) ; XOverradelxOverPadβ) j ) CApsStain: :-CApsStain () { ) //static CAβastain Hematoxylin! •He.matoxylin" , CMCVCOLX3R (240.0 , 0.9.0.8) , 200.273 ) ; //static CApsStain Eosin! "Eosin" , CHSVCOLO (322.0.0.85, 0.84) , 310 , 3HS) ; static CApsStain Hematoxylin ( he atoxylin" . CHSVCOLOR ( 241.0 , 0.64, l .-wr, 190.285) ; static CApsStain Eosin I "Eosin" , CHSVCOLO (32 .0 , 1.0 , 1.0) , 300 , 395) ; static CApsStain TBlus ( "Toluidine Blue", CHSVCOLOR (234.0.0. S3 , 0.86) , 205, 250); static CApsStain FRedCFast Red", CHSVCOLORI0.0. S5 , 0.90 ) , 310, 385); static CApsStain DFStainlCDFStaml' , CHSVCOLOR 10.0 , 1.0, 1.0), 310, 385); static CApsStain DFStam2 ("DFStamΣ", CHSVCOLOR (120.0. 1.0, 1.0), 90. 150); static CApsStain EFFreelCDF Free 1", CHSVCOLOR(0.0 , 1.0, 1.0), 0, 359); static CApsStam DFFree2 ("DF Free 2", CHSVCOLOR (120.0, 1.0, 1.0), 0, 359); static CApsStain DFFree3 ("DF Free 3", CHSVCOLOR (240.0, 1.0, 1.0), 0. 359); static CApsSta DFFree4 ("DF Free 4", CHSVCOLOR (300.0, 1.0, 1.0), 0, 359); static CApsStain BFFreelCBF Free 1", CHSVCOLO (240.0 , 0.9. 0.8), 0, 359); static CADsStam BFFree2 ("BF Free 2". CHSVCOLO (322.0 , 0.8S, 0.84), 0, 359); static CApsStam EFFree3 CBF Free 3", CHSVCOLO ( 120.0, 1.0, 1.0), 0, 359); static CApsStain BFFree4("BF Free 4", CHSVCOLOR! 300.0, 1.0, 1.0), Q, 359); static CApsStam EVGCEVG", CHSVCOLOR ( 2d0.0. 0.31, 0.82), 230, 250, CHSVCOLOR ( 240.0 , 0.0, 0.0), 127, FALSE) ; static CApsStain EVGCouncer ( "EVG Counter", CHSVCOLORI360.0, 0.9, 0.83), 340, 380); CApsStamSet HandE ( "Hematoxylin & Eoain", 2, TRUE, StHematoxylin, iEoβin) ; CApsStainSet TolBlue ( "Toluidine Blue", 1, TRUE, fcTBlue) ; CApβStainSeC FaStRedl "Fast Red", . , TRUE, fcFRed) j CApsStamSet DFDuaK'Dual DF Stain Set" , 2. FALSE, Σ-DFStainl, «.CFStaιn2) i CApsStamSet DFMonoCMono DF Stain Set" .1. FALSE, -.DFStainl) ; CApsStamSet ApsDFRaw( "ADS Raw"); CApsStamSet DFFree("DF Free" ,4, FALSE, iDFFreel . K,-.rFree2, tDFFree3. CDFFree4) ; CApsStamSet EFFreeCBF Free" .4, RUE, fcBFFreel, £3FFree2 , &3FFree3 , £.BFFree4) ι CApsStamSet SFGEVG( "SFG EVG" , 2, TRUE, 4EVG, SEVGCounter) ; CApsStainSet *stainSeta[] = { tHandE, STolBlue, fcFas Red, lifndef OUTSIDE_RELEASE ISFGEVG, S-DFDual, tDFMono, tDPrree, StBFFree , #endif //OUTSIDE_RELEASE -ApsDFRaw, NULL )> mt NumstamSets ■ sizeof (Stam≤eta ) / βizeof (StainΞets [ 0 ] ) -1 ; CApsStamSet "Finds tamSet ( const char 'name ) ( CApsStainSet "ssVec ■ S tainSets j while CssVec) { i ( I stricm lna e , CssVec ) ->Narae ( ) ) ) return *ssVec ι ssVec++ ; ) return NULL ; ) static CApsLUT StainX-tlTS (MAXSTAINS) ; void CApsStainSet : : RestorβDe aultColors ( ) ( int ns ■ NumStu-.na ( ) ; CApsStam 'stain; staι.n->CurrentColor (stam->Def aultColor ( ) ) ; void CApsStainSet: :RestoreUse:a^cauitColors ( ) ( int na = Nums Cains () ; CApsStain 'stain; fordnt s«0;s<ns;s++) ( stain » stai (s) ; stain->CurrentColor ( stain->lTserDef aul tCσlor ( ) ) ) BOOL CApsStainSeC: :SaveUsβrDef aul tColors (void) ( int na ■ Nu S ains () -1; CApsStain 'stain; HSVCOLOR clr; i ( llniSecsection ("Stains", RUE) ) return FALSE; if (ns<0) return FALSE; do ( stain ■ Stain(ns); clr * stain->CurrentColor ( ) ; stain->UBerDefaultColor (clr) ; if (!InisetHSV( (char ') scam->Name () , clr. h, clr.s, clr.v) return FALSE; ) while (na--) ; return TRUE; BOOL CApsStainSet : :LoadUserDefaultCclors (void) ( CApsStain 'stain; int ns ; double h, s, v; BOOL rv • FALSE; if (llniSecsection ("Stains" .FALSE) ) return rv; if((ns « NumStains ( ) ) ) { ns— ; do ( stain - Stain(ns) ; i (IniGecHSVt (char ") 3tain->Naroe ( ) ,i ,M, &v) ) { εtain->U B βrDe£aultColor (CHSVCOLORlh.s.v) ) ,- stain-> C urrentColor( 5 tain->UserDe aultC(-lor() ) rv ■ TRUE; ) ) while (ns—) ; return rv; void CApsStainSet: :BuildLUTS (int scainIdx/*=-l*/) ( HSVCOLOR noS ain; HSVCOLOR stainColor; CApsStain 'stain; CApsLUT *lUtl if (stainldx<0) { int ns ■ NumStains () -1; do { stain s stain(ns) ; lut - & (stainLUTS[ns) ) ; stainColor - s ain->CurrentColo ( 1 ; noStain.h ■ stainColor.h; //NASTY HACK ALERT - h i e chock (special treatment) If (BrightFicldO / » &£.( this! *J.Handr.) */) ( noStain.s ■ 0.0; noStain.v « 1.0; ) ύlϊ { noStain.s = stainColor.a; noStain.v « 0.0; ) if (staιn->XOverVal < ) ) { lut->Build ( noStam, stainColor , 0 stam->XOverVaI ( ) ) , if (staιn->XOverFade() ) { lut~>Buιld ( stainColor --aιπ->XOv-rColor() , scam->XOverVal 0 + 1,255) , } else ( lut->Buιld ( scam->XOverColor 0 , s ain->XOverColor ( ) , scaιn->XOverVnl () + 1,255) ) else ( luc->Buιld ( noStaιn,scamColor) ; ) ) while (ns—) ; ) else ( sca » Stain (stainldx) ; lut » StainLUTS Istainldx] ) , stainColor - scaιn->CurrentColor ( ) , noSta .h - stainColor. ; //NASTY HACK ALERT - h £. e check (special treatment) if (Brightfield ( ) /*&£. ( this ' =&HandE) »/ ) { noStain.s » 0.0; noStain.v - 1.0; ) else ( noStain.s » stainColor. s; noStain.v « 0.0; ) if (stam->XOverVal() ) { lut->Buιld(noS ain, stainColor.0.stain->X0verVal () ) , if (stam->XOverFade() ) ( lut->Buιld (stainColor, ε am->XOv»-rColor 0 , stain->XOverVal 0+1,255) ; ) else ( lut--•Build (sta ->XOverColor 0 , stam->XOverColor ( ) , stam->XOvtrVal () +1,255) ; ) ) else { lut->B il (noStain, stainColor) ; ) ) ) void CApsStainSet: :StaιnBuffer (APSCLR *src,APSCLR 'dεt.mt plx.int channels) { i (isrcl I idst) return; pιx~ ; // / /NASTY HACK ALERT1 ' // / /if (this— ScHandE) { // BYTE *βb - (BYTE ') (src+piX); // int εl - StmnSrc(O) ; // inc s2 « stainεrc(l); // CApsLUT 'lutl = J.(StainLUTS[0] ) ; // CApsLUT *lut2 « 4(StainLUTS(l] ) ; // BYTE black; // do ( // black » inverccolor) (BYTE)MAX(sb(sl) .sb(«2) ) ) , * -.. // dstlpix] - AddColors(lutl->Lookup(sb(sl) ) lut2->Lookup |sbts2] ) ,bl-n-k ; // sb — sizeo (APSCLR) ; // ) while (pix— ) ; / / return; //) switch (MIN (channels, umStains ()) ) ( case 0: { βrtColor(βrc(pιx) ) , acecolo lsrctpix] ) ; ) while (pix--) ,-' //memcp (dst.src, (ρix+1) 'sizeof (APSCLR) ) ; ) break; case 1: { BYTE *sb = ((BYTE *) (src+pix) ) ; int si = Stainsrc(O); CApsLUT *lut - &(StainLUTS(0] ) ,- do { dstlpix) = lut->Lookup (sblsl] ) ,- ab -» sizeof (APSCLR) j ) while (pi — ) ; ) break; case 2: C BYTE 'sb - (BYTE *) (src+pix) ; int si - stainSrc(O); int s2 « ΞtainSrc(l); CApsLUT » lutl = t(StainLUTS[0] ) ; CApsLUT » lut2 = -.(StainLUTSll] ) ; if (BrightFieldO ) ( do { dstlpix] = OverlayColors (lutl-i-Lookup (sblsl] ) , luc2->Looku <sb[s2] ) ) ; sb -= sizeo (AFSCLR) ; } while (pi — ) ; ) else { do ( dstlpix] - AddColors (lutl->Lookup (sblsl] ) , lut2->Lookup (sb[s2 ) ) ) ; Sb — sizeof (APSCLR) j } while (pix--) ; } ) break; case 3 : ( BYTE *sb = (BYTE *) (src+pix); int si ■ StainSrc(O); int s2 • StainSrc(l); int β3 » StainSrc(2)ι CApsLUT *lUCl » &(StninLUTS[0]) ; CApsLUT 'lut2 - & (StainLUTSll] ) , CApsLUT *lut3 » 4(StainLUTS(2J ) ; if (BrightFieldO ) ( do { dstlpix] ■= OverlayColors (lutl->Lookup (sblsl] ) , lut -*Loolcup (sb(s2] ) , lut3-->LOOKUP ( sb[s3]) sb -« sizeof (APSCLR) ; ) while (pix—) ; ) else { do ( dstlpix] = AddColors (lutl->Lookup (sblsl] ) , luc2->Lookup (sbls2] ) , lut3->Lookup(sbls 3])); sb — sizeof (AFSCLR) while (pix--) ; break; case 4 : BYTE 'sb - (BYTE *) (src+pix); int si - StainSrc(O) int s2 = Stain--rc(l) int s3 M Stair-SrcC.) int a4 - StainSrc (3) CApsLUT 'lutl - ϋStainLUTSlOl) ; CApsLUT •lut2 = - (StainLUTSll]) CApsLUT *lut3 - i(StainLUTSl2]) CApsLUT *lut4 = StaιnLUTS[3] ) if (BrightFieldO ) { do < dstlpix) = OverlayColors (lutl->Lookup (sblsl] ) , lut2->Looku (sb,s2] ) , lut3->Lookup(sb(s3] ) , lut4->Lookup<εb[s4] )) sb -= sizeof (APSCLR) ; ) while (pix-- )*" ) else { do { dstlpix) = AddColors (lutl->Looku (sblsl] ), - uc2->Looku (sb(s2) ) lut3->Lookup(g)3(s3] ) , luL4->Looku (sb(sd) ) ) , sb -- si2βof (APSCLR) , } while (pi — ) ; ) ) break; ) CApsStamSet: :CApsStainSet ( ) ( memset (this, 0, sizeo ('this) ) ; } CApsStainSet: :CApsStamSe (const char 'name, int numS ains , BOOL brightField, CApsStain 'stao.nl. CApsStam 'staιn2, CApsStain 'staιn-3 , CApsStain *stamd) ( memset (this, 0, sizeo ('this) ) ; Name (name) ; NumStains (numStains) ; //this is the default // //this should be re-set //after a dataset has been loaded. //the setting should correlate //to the processes (optical & chemical) //used to generate the data //as well as the color flags //that are set the file, // StainSrc (0, 2) ; StainSrc (1,1) StainSrc (2,0) StainSrc (3,3) BrightFiel (brightField) ; Stain(O.stainl) ; Stain (l,stain2) ; Stain(2,sta 3) ; Stain(3,βtaιn4) ; CApsStainSet: :-CApsStamSet () { ) BOOL LoadAllΞtamUserDefaults (void) ( CApsStainSet "ss * StainSets; lttt nss = NumStainSets; BOOL rv » FALSE) if (llni≤etSectionl "Stains • .FALSE) ) return rv; do { i ( ( »ss) ->LoadUserDβ ultColors ( ) rv « TRUE; ss++; ) while(— ϊ_ts ) ; return rv; ) /*** End of file: apsβtain.cpp **"/ static char apslut_ld[] - "Sic: apslut.cpp, 1.6 1999/05/10 18:39:15 bean Exp $"; ♦include wmdows.h> ♦include <wmdowsx.h> ♦include <ιo.h ♦include <fcntl.h> ♦include <stdio.h ♦include <βtrιng.h> .include "cellvue.h" ♦include 'apεdll.h" ♦include "tabarray.h" ♦include "ini.h" ♦include "apslut.h" ♦include " color.h" ♦include "fadebar.h" ♦include "apsstain.h" /* global instance handle for this module */ HINSTANCE hModule * 0 ; /' instance data pointer (only one allowed for th- s module) */ LPΛPSLUTINST pslnst - 0; CApsStainSet 'C\ιrrentSta.inSet « NULL; BOOL ConstUpdate = FALSE; BOOL DontDoCB = FALSE) LPAPSSLICE laβtSlice ■ NULL; LPAPSSLICE clean≤lice « NULL,- cypedef long (_cdecl 'MsgHandler) (HWND,UINT,WPARAM,L?ARAM) ; BOOL WINAPI DllMainf HINSTANCE, DWORD, LPVOID ); LRESULT CALLBACK MessageProc! KWND hWn , UXNT __s . . WPARAM wParam. LPARΛM lPαram ); /'" ' "'" "•"••-" ♦ . * ** / /' list of available plugms in this module */ extern "C" declspβc (dUexport) APSPLUCINFO PlugmList ( ] - ( ( "apβ_2D_lut_plugιn" , "1.0", "Default 2D LUT Plugin" , "2D", (MsgHandler) S-MeβsageProc NULL ); / * / /* save module handle when the OS loads the plugin */ BOOL WINAPI DllMai ( HrNSTANCK hl stDU., DWORD dwReason, LPVOID IpReserved ) ( /* save global instance handle */ hModule » hlnstDLL; return TRUE; ) inline void LUTConvβrt (void) { / /if ( lastSlice->dwFlags-PLWFLAGS_LUT_CCNVERTED) // return; p=lastSiice->dwWidl:h'laEtSlice->dwHeight; CurrentSCainSet->StainBuffer( (APSCLR " ) cleanSlice->psData , ( APSCLR ') lastSlice->psData,p,lastSlice->dwChannels) ; i (CurrentStainSec «» SApβDFRaw) ( lastSlice->dwFlags = clean≤lice- dwFlags; lastSlice->dwRGBFlagβ = c!eanSlice->dwRGBFlags; lastSlice->dwChannela = cleanSlice->dwChannels; ) else { //mark the slice as LUT converted lastSlice->dwFlaga I =PLUGFLAGS_LUT CONVERTED; //set the slice flags to reflect that it is now 3 color rgb data lastSlice->dwRGBFlags = RGBFLAGΞ_RED | RGBFLAGS_GREEN | RGBFLAGS_BLUE; lastSlice->dwChannela - 3; ) //recopy the clean data to the slice we will send down the chain //we have to always send the slice we got, not a duplicatel //inline void CleanSlice (void) { // i (laStSlice->dwFlagβϋPLUGFLAGS_LCT_CONVERTED) ( // memcpy (lastSlice->pεData, cleanSlice->psData, // (lastSlice->dwWidth*lastSlice->dwHeiflhc) 'sizeof (APSCOLOR) ; // lastSlice->dwFlags ■ cleanSlice-s-dwFlagβ; // lastSlice->dwRGBFlags » cleanSlice->dwRGHFlags; // laεtSlice->dwChannels » clβanSlice- dvCha-.nels; // ) //) void Refreshslice (void) { if ( IlastSlice) return; LUTConver ( ) ; ProduceOrthoSlice( lostslice , pslnsc->hwnd ) ) void EnableDe aul sBut ons (BOOL enablβ»TRUE) { HWND hwnd - pslnst->hDlgWnd; EnableWindow(GetDlgItem(hwnd,IDC_RESTOREBTN) .enable) ; EnableWindow(GetDlςItεm(hwnd.IDC_ORIGDEFAULTSBTN) .enable) ; EnableWindow(GetDlgItem(hwnd,IDC_SAVEASDEFAULTSBTN) .enable) ; } void Load≤taiι-SetCombo(iπt) ; void SecCurrentStainSetlCApsStainSet ') ; /**" ».».«. ,...♦.+ •*..**,/ /* main message handler for the plugin */ LRESULT CALLBACK MeβsageProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPABAM Iparam ) ( static BOOL newD&ta ■ FALSE; static BOOL firstDS « TRUB; switch I uMsg ) C case WM_APS_INIT: return FALSE; case WM_DESTROY; UnRegiaterFadeBa (hModule) ; if (cleanslice) DβstroyOrthoSlice (CleanSlice) i return FALSE; case WM-_APS_CONSTRUCTOR: /* initialize an instance of parameter data '/ RegisterFadeBar (hModule) ; pslnβt = (LPAPSLUTINST)apsmallocO( sizeof (-.PSLUTINST) ) ; pβlnst->hwnd » hwnd; CreateTabDialog! "SECTION (2D)", "Stain". hModule, (LPVOID) sl.iat, MAKErNTRESOURCE (IDD_D lA OOl) . (OLGFROC) DiβloπlProc ); return (LONG)hWnd; case WM-^PS_NHM_DATASS»*s«,OADED : newData « TRUE; return FALSE; case WM APS_SLICE_PACKET: ( LPAPSSLICE slice* ( PAPSSLICEJwParam; if (cleanSlice) ( DeβtroyOrthoSlice (cleanSlice) ,- cleanSlice ■ NULL; ) lastSlice » slice; cleanSlice » DuplicateOrthoSlice(βlice) ; //new data to adjust to if(newData) ( newData = FALSE; if(firstDS) ( EnableWindow(GtCDlgItem(psInsC->hDlgWnd,IDC_ΞTAINSl-T_COMBO) ,TRUE) ; LoadStainSetCombo ( (int) slice->dwChannelβ) ; //if this is the first dataset ever or //we are not in raw (we don't change out of raw normally, one size fits all) //but we START in raw mode I, assume a stain is wanted. Whew. if (firstDS| |CurrentStainSet!=--ApsDFRaw) { iff(firstDS) ( tirstDS ■= FALSE) 5 if (CurrentStainSet- NumStains () l » (int) Blice->dwChannels) ( int 33"0; _or (sβ;ββ<NumStainSets;ss++) ( if (StainSets iss ) ->Numstains ( ) « (int ) slice->dwChannels) { brea ; ) ) // //sec to raw if no other stain set works (fcApsDFRaw) ; SetCurrentStalnSe lStainSets [ss] ) ; ) ) ) ) RefreshSliceO ; return FALSE; ) break; ) /* call default windows proc */ return DefWindowProc ( hWnd, uMsg, wParam, lParaia ) , • ) void UpdateFadeBars (void) ( HWND hwnd « psInst->hDlg nd; CApsStain 'stain - CurrentStainSet---Stain(CurrentStαinΙdx) : HSVCOLOR "activeColor » stain ? stain->CurrentColorPtr : NULL; HSVCOLOR thSV = CO.0,0.0,0.0), • HSVCOLOR thsv2 - {0.0,0.0,0.0}; HWND hFB; i (activ«color) ( thβv - 'activeColor; thsva » thsv; hTΞ - GetDlgItera(hWnd.I-" "ROEBAR) , if (CurrentStain-Set->Bn^^"ield( ) ) ( thsv2.s = 0.0; thsv2.v - 1.0; ) else { thsv2.s = 1.0; thsv2 -v = 0.0; ) SendMer.sage(hFB,WM_FSSETLCOLOR.O. (LPARAM) fcth3v2 ) ; thsv2 = thsv; SendMessage (hFB. WM_FBSETRC0LOR,0. (LPARAM) fcthsv2) ; RβdrawWinάowlhFB. ULL. NULL. RDW_INVAL.IDATE| RDW-.UPDATENOW) ; hFB = GetDlgItem(hWnd.IDC_HUEFADE) ; thsv.h = stain ? (double) stam->HueMin( ) : 0.0: SendMeaeage( FB WM_FBSETLCOLOR.0. (LPARAM) fc thsv) ; thsv.h = stain ? (double) 3tain->HueMa ( ) : 0.0; sendMessage (hFB.WM_FBS-rτRcθLθR,o, ILPARAM) fc hsv) ; thsv.h=thsv .h; Re r awwmdow ( hFB , ULL. KUL . RDW_ INVALIDATE | RDW-.UFDATENOW) ; hFB - G*tDlgItem(hWnd. IDC_SATFADE) , CΛSV.S=0.0; SendMessage (hFB. WM_FBSETLCOLOR,0, (LPARAM) fcthsv) ; thsv.8=1.0 ; SendMeeβage(hFB,WM_FBSETRCOLOR.0. (LPARAM) fc thsv) ; tUsv.s=thsv2.S; Redrawwmdow ! hFB .NULL. NULL. RDW_INVA IDATE( RDW_UPnATENOW) ,- void HandleSliderMesaage (HWND hWnd, iπt nScrollCode. int nPos. HWND hwndScrollBar) { char numStr (32] ; int dPos»0 ; HWND hwndEdit = NULL; lQO .0 ; ; = CurrentStamSet->Staιn(C--rrent≤tair.Idx) ->CurrentCθlorPtr ( ) ; i (DαntDoCB) return; f (hwndScrollBar — GetDlgItem(hWnd.IDC_HUΞSLIDER) ) { hwndEdit - CetDlgltemlhW-id. IDC_HUETEXT) ; valP=--(aet vcColor->h) ; divisor=l .0 ; fsαt="%d"; maxDisp = 360; ) else if (hwndScrollBar == GetDlgltemfhWnd. IDC-.SATΞLIDER) 1 ( hwndEdit = GetDlslteroihwnd. IDC_SATTEZT) ; valP=fc (actιveColor->sl ; ) else if (hwndScrollB-ir == GetDlgItfm(hWrif., IDC_VALSLIDER) ) ( hwndEdit = GetDlgltemlhwnd. IDC_VALT2XT) ,- valP=fc(actιveColor->v) ; ) GetScrollRange ( hwndScrollBar, SB_CTL, s_3u.n.--max) , switc d-ScxollCode) ( case SB_PAGEI-£FT: dPos-=20; case SB_PAGERIGHT : dPos+rll; case ≤B_LINELEFT: dPos--2; case SB_ INERIGH : dPos+=l; (hwndScrollBar, SB CTL) + dPoj ~" case Sets -rollPoe ( hwndScrollBar, SB_CTL.nPos. TRUE) ; sprint ( nu-r-Str.£mt.nPos%maxDιβp) ; SecwmdowText (hwndEdit. nu Str) ■ "valP = (doublelnPos/divisor; UpdateFadeBars ( ) ; if ( ICons tupdatefct ! arrowKey) brea ; case SB_ENDSCROI-L: CurrentStaιnSet->BuιldL-JTS (CurrentStainldx) , RefreshSlice () ; ) break; ) ) void ReloadHSVTexts () ( HWND hwnd - psInst->hDlgWnd; CApsStain "stain = CurrentStainSet->Stain(CurrentStaιnIdx) ,- HSVCOLOR 'activeColor = stain ' sr.aιn->CurrentCαlorPtr ( ) : NULL. mt hπαn = stain ? s ain->HueMιn( ) : 0; int hmax = stain ? stain->HueM-x() : 0 ; char numstr(32].- int h = 0, s = 0 , v = 0 j i (activeColor) ( h » (int) activeColor->h; s = (int) (actιveColor->B*100.0) ,- v - (int) (activeColor->v'100.0) ; ) spnntf (nu Str. "%d",h*361J ; Setw dowText (GetDlgItem(hWnd.IDC_HUETEXT) .numStr) ; sprint (numStr. "*d*%" , s) ; SecwmdowText (GetDlgItem(hWnd.IDC_SΛTTEXT) .numstr) ; aprintf (numStr, "%d%f ,v) ; SetWindovText (GetDlgItem(hwnd. IDC VALTEXT) .numStr) , ιf(h<hmin) { h+=360; j else if(h>hmax) { h-=360; } if (IaWindowEnat>led(GetDlgItem<hWnd.IDC_HUESLXDER) ) ) ( SetScrollPoo(GetDlgItem(hWnd.IDC_HUESLIDER) , SB_CTL . h , TRUE ) SetScrθllPoε(GetDlgIte-n(hWnd,IDC_SATΞLIDER) , SB_CT , s . TRUE ) SetScrollI , os(GecDlgItfnι(hWnd,IDC_VALaLIDER) . S__CT_, v, TRUE) ) ) static int Sta RadloIdε [MAXSTAINS + 1) = ( IDC-.S1C0L0RRADI0. IDC_S2COLORRADIO. IDC_S3C0LORRADI0, IDC Si COLORRADIO , 0 ) ; void SetCurrentSCamdnc stainldx) ( CurrentStamset; tDlgItem(pεI»-sc->hDlgWnd. τr> _HUESLIDER) : Currcntstainldx - stainldxT""" stain = ss->Stain ( stainldx) , • if (stain) { -ιmin = stain->HueMin() ; hmax = stain->HUeMax( ) ; ) SetScrollRange (hueSlider. SB_CTL. hmin, hmax, TRUE) ; ReloadHSVTexts ( ) ,- UpdateFadeBars ( ) ; static void EnableHSVSliders (BOOL flag) ( EnableWindow ( GetDlgItem ( pBln3t->hDlgWnd.IDC-_HUESLIDER) .flag) ; EnableWindow ( GetDlgItem(psInst-> Dlg nd. IDC.-SATSLIDER) . flag) ; EnableWindow(GetDlgItem(psInβt->hDlgWnd, IDC_VALSLIDE-R) . flag) ; void LoadStainSetCombodnt ch-αis) ( int ssi; int nss = Nu StainSets; HWND comboBox = GetDlgItem(psInst->hDlgWnd.IDC_STAINSET_COMBO) ; s; nt coraboldx=0; SendMessage (comboBox,CB_RESETCONTENT.0,0) ; for (ssi = 0; sei < nss; ssi++) ( ss « StainSets (ssi] ; //if (SS->NumStains ()=«0| | ss->NumStain3 ( ) <:chanj) ( comboldx=SendMeseage(comboBox.CB_ADDSTRING. 0. (LPARAM) aβ->Name ( ) ) ; SendMessage (comboBox. CB_SETITEMDATA, comboldx, (LPARAM) S3); //) ) ) void SetCurrentStainSet (CApsStainSet *sβ) { KWND radio; int s; SendMeeeage (GetDlgI em(psInst->--DlgWnd. IDC_ΞTAINSET_COMBO I , CB_SELECTSTRING , -1, (LPARΛM) ss-s-Name I ) ) ; CurrentStainSet = ss; if (Bs->NumStains () ) ( EnableHSVSliders (TRUE) ; if (ss->Num≤taina()>l) ( int ns = εs->NumStains () ; f or(s=0; s<ns;s++) { radio = Get01gItem(p£lnst->hDlgWnd, StainRadioIda (ε] ) ; SetWindowText (radio, ss->S tai (β) ->Name( ) ) ; Showwindow ( radio , SW_SHOW) ; ) whiletStainRadioIdsls] ) ( ShowWindow(GetolgItem( C 3ln3t->--Dlgwnd. StainRadioIda [s] ) , SW_HIDE) ; s++; ) ) elee { f or (s=Q ; StainRadioIds [ε] ;s++) ShowWindow(GetDlgItem(psInεt->hDlgv d, StainRadioIds [s] ) .SW.HIDE) ; ) SetCurrencStain(O) ; ss->BUildLUTS() ; EnableDe aul βButtons (TRUE) ; ) else ( Enabl eHSVS 1 iders ( FAL-1 EnableOefaultβButcong f^ALSE) ; ReloadHSVTexts d ; UpdateFadeBars ( ) ; SendMessageToAllP:uginInotances (WM_ J APS_BRIGHTFIELD_J-ODE, 0 , ss->BriςhtField ( ) ) ■ ) / '*"d'i"alog box proc •/ * " ' / BOOL DialoglPror( HWND hWnd, UINT dwMε , WPARAM wParaia, LPARAM IParam ) static BOOL go Focus = FALSE; switch ( dwMsg ) ( case WM-.INITDIAL0G : psInst->hDlgWnd = hWnd; LoadAllStainUserDefaults ( ! ; EnableHSVSliders (FALSE) ; EnableDe aultsButtons (FALSE) ,- SendMessage (GetDlgltemlhWnd. IDC_FADEBAR) ,WM_FBSETMODE, 0 ,FBM_HΞV) ; SendMessage (GetDlglter hWnd, IDC_HUEFADE) . WM-.FBSETMODE.0 , FBM_HSV) ; SendMessage (GetDlgltemlhWnd. IDC_SATFADE) .WM--FBSETMODE .0. FBM-.HSV) ; SendMessage <GetDlgItem(hWnd, IDC_VALFΛDE) ,WM_FBSETMODE, O.FBM_HSV) ; SetScrollRange (GetDlgltemlhWnd. IDC_SATSLIDER) .SB_CTL.0.100.TRUE) ; SetScrollRange (GetDlgItem(hwnd, IDCVALSLIDER) ,SB_CΪT., 0.100, TRUE) ; EnableWindow(GetDlgItem(hwnd. IDC_STAINSET_COMBO) , FALSE) ; SetCurrentStain≤e (fcApsDFRaw) ; break; case WM_RBUTTONDO N: if ( (wParamJ.MK_C0NTROL) fcfc (wPar mfcMK-.SHIFT) ) ( ConstUpdate=!CoπstUpdate; if (ConstUpdate) ( 8eep<880.250) ; ) elee < Beep(440.250) ; ) ) brea ; case WM_COMMAND: switch ( LOWORD(wPara-tι) ) ( case IDCSICOLORRADIO : SetCurrentStaιn (O) ; break; case IDC_S2C0L0RRADI0 : SetCurreπtStain( l) ; break; case IDC_S3COLORΛADIO : SetCurrentstain(2 ) ,• Jareak: case IDC_S4COLORRADI0 : SetCurrentStain (3 ) ,- break,* case IDC_STAINSET_COMBO : switch (HIWORD (wPara ) ) ( case CBN_SELCHANGE : int CUrSel = SendMessage ! (HWND) lP-.ra-π. CB_GETCURSEL. 0 . 0) ; CAusStamSet * £S - (CApsStamSet • ) SendMessage ( (HWND) lParaια. CB_GETITEKDA TA. (WPARAM) curSel . 0) ; ir s! -CurrcntStainSec) ( setCurrent≤cainSet (ss) , Refresh≤liceO ; ) ) break; ] __break;_ case IDC_SAVEASDEFAULTSBT : if I IcleanSlice) break; CurrentStainSet->SavnUserDefaultColorβ( ) ; break; case IDC_ORIGDEFAULTSBTN: if ( IcleanSlice) CurrentStainSet->Rt_storeDefaultColors ( ) ; ReloadHSVTexts ( ) ; UpdateFadeBars ( ) ; CurrentStainSet---BuildLUTS O ; RefreshSlice ( ) ; break; case IDC-RESTOREBTN: if ( IcleanSlice) break; CurrentStainSet->RestoreUserDefaultColora ( ) ,- ReloadHSVTexts ( ) ; UpdateFαdeBars ( ) ; CurrentStain≤et->BuildLUTS () .- Refresh≤liceO ; Refresh≤lice ; break; case ΪDCANCEL: EndDialogl hWnd. FALSE ); break; ) break; case WM_HSCROLL; HandleSliderMeeeagefhWnd.LOWORDIwParam) , HIWORD(wParara) , (HWND) IParam) ; break; } /* don't close the dialog cox '/ return FALSE; ) /*" End of file: apslut.c *"/ apslut . h tfifndef _APSLUT_H_ #define _APSLUT_H_ #if ef cplusplus // pre vent name mangling extern "C" { #endif // include resource dialog headers that were generated // by Visual C++ #include " .. \reε\dialogl .h" // defines // structures // 2D instance data typedef struct _APSLUTINST ( HWND hwnά; KWND hDlgWnd; apslut.h // // <-- all your instance data // } APSLUTINST, *LPAPSLUTINST; // externs // module handle extern HINSTANCE hModule; * ■ *•** + ★** j II prototypes // apslut.c LRESULT CALLBACK MessageProc ( HWND hWnd, UINT uMsg, WPARAM wPar ain, LPARAM IParam ) ; BOOL DialoglProc( HWND hWnd, UINT dwMsg, WP ARAM wParam, LPARAM IParam ) ; UINT APIENTRY OFNHookProc ( HWND hdlg, UINT uiMsg, WPARAM wPa ram, LPARAM IParam ) ; #ifdef cplusplus // pre vent name mangling } lendif //cplusplus #endif //_APSLUT_H_ /*** End of file: apslut.h ***/ apsstain . h Kifndef _APSSTAIN_H_ tdefine _APSSTAIN_H_ - include "ApsFileTypes .h" const int MAXSTAINS = 4; class CApsLUT { private: APSCLR m_Entrieε[256] ; inline APSCLR *Entries (void) { return m_Entries ; } public : void Build (HSVCOLOR firstColor , HSVCOLOR lastColo , int firstldx =0,int lastldx=255) ; inline APSCLR Lookup (BYTE idx) { return Entries () [idx]; } inline APSCLR BaseColor (void) { return Looku (255 ) ; } CApsLU ( ) ; -CApsLUT ( ) ; } class CApsStain { private: apsstain.h const char *m_Name; // //initial color // HSVCOLOR m_Def aultColor; HSVCOLOR m_-UserDef aultColor ; int m_HueMiπ; int m_HueMax; / / //neither of these are //adjusted from the UI! // int m_XOverVal; HSVCOLOR m_XOverColor; //is crossover color //solid from xover point to end //or does it fade from //last value of base color toward //the xover color BOOL m_XOverFade; // //current color (tweaked via sliders) // HSVCOLOR m_CurrentColor; public : inline const char 'Name (void) const { return m_Name; } inline const char *Name (const char 'name) { return m-_Name = name ; } inline HSVCOLOR DefaultColor (void) const { return -_DefaultColor ; } inline HSVCOLOR Def ultColor (HSVCOLOR clr) { m_Def ultColor = clr; return π_DefaultColσr; } inline HSVCOLOR UserDefaultColor (void) const { return m_UserDefaultColor; } apsstain.h inline HSVCOLOR UεerDefaultColor (HSVCOLOR clr ) { m_UserDe£auitColor = clr; return m_UserDefaultColor ; } inline int HueMin (void) const ( return m_HueMin; } inline int HueMin (int hm) { return m_HueMin = hm; } inline int HueMax (void) const { return m_HueMax; } inline int HueMax (int hm) { return m_HueMax = hm ; } inline HSVCOLOR CurrentColor (void) const { return m_CurrentColor; } inline HSVCOLOR *CurrentColorPtr (void) { return &m_CurrentColor; ) inline HSVCOLOR CurrentColor (HSVCOLOR clr) { return m ^ CurrentColor = clr; } inline HSVCOLOR XOverColor (void) const { return m_XOverColor ; } inline -ιsveui-,υκ xuvereoior (HSV C O L O R c l r ) ( return m_XOverColor = clr; } inline int XOverVal (void) const { return ra_XOverVal ; } inline int XOverVal (int v) { return m_XOverVal = v; } inline BOOL XOverFade(void) const { 57 - apsstain.h return m_XOverFade; } inline BOOL XOverFade (BOOL f) { return m_XOverFade = f, } CApsStain ( ) ; CApsStain (const char *name, HSVCOLOR defColor, mt hueMin, int hu eMax) ; CApsStain (const char *name. HSVCOLOR defColor, int hueMin, int hu eMax, HSVCOLOR xOverColor, int XOverVal , BOOL xOverFade) ; -CApsStam ( ) ; }; class CApsStainSet { private : const char *m_Name ; int m_NumS tarns ,• BOOL m_BrightField; CApsStam *m_Stains [MAXSTAINS] ; t m_StainSrcs [MAXSTAINS] ; public: inline const char *Name(void) const { return ιu_Name; ) inline const char 'Name (const char "name) { return m_Name = name; } inline int NumStains (void) const { return ιrt_NuιaS ains; } inline int NumStains (int ns) { return m_NumStains = ns; } inline t StainSrc (mt stainldx) { if ( (unsigned) εtamldx< (unsigned) NumStains ( ) ) return m_StamSrcε [stamldx] ; return -i; } inl ine mt StainSrc ( int stamldx, mt channelldx) { if ( (unsigned) stainldx< ( unsigned) umS ains ( ) ) return m_StaιnSrcs [ stamldx] = channelldx; color . h #ifndef _COLOR_H_ #define _COLOR_H_ typedef struct { double h; double s ; double v; } HSVCOLOR; typedef struct { double r; double g; double b; } DRGBCOLOR; _inline int MI (int a, int b) { return a<b?a:b; } --.inline int MAX (int a, int b) { return a>b?a:b; } _inline double DMIN (double a, double b) { return a<b?a:b; } _inline double DMA (double a, double b) { return a>b?a:b; } .inline int ABS(int a) { O 00/70541 color .h return a<0?-a:a; inline void DRGB2KSV(DRGBCOLOR *drgb, HSVCOLOR *hsv) { double max=DMAX(DMAX(drgb->r,drgb->g) ,drgb->b) ; double min=DMIN(DMIN(drgb->r,drgb->g) ,drgb->b) ; if ( (hsv->v=max) !=0.0) { hsv->s= (max-min) /max; } else { hsv->s=0.0; hsv->h=0.0; return; } if ( !hsv->ε) { hsv->h=0.0; return; } if (drgb->r==max) { hsv->h = (drgb->g-drgb->b) / (max-min) ; } else if (drgb->g==max) { hsv->h = 2.0 + (drgb->b~drgb->r) / (max-min) ; } else if (drgb->b==max) { hsv->h = 4.0 + (drgb->r-drgb->g) / (max-min) ; } hsv->h*=60; if (hsv->h<0.0) [ hsv->h+=360.0; ) else if (hsv->h>=360.0) { hsv->h-=360.0; } } _inline COLORREF DRGB2COLORREF (DRGBCOLOR *drgb) { return RGB ( (int) ((drgb- r*255.0)+0.5) , (int) ((drgb->g*255.0)+0.5) , (int) ( (drgb->b*255.0)+0.5) ) ; } _inline void COLORREF2DRGB (COLORREF cr.DRGBCOLOR *drgb) { drgb->r= (double) GetRValue (cr) /255.0 , drgb->g= (double) GetGValue (cr) /255.0, drgb->b=(double ) GetBValue (cr ) /255.0, ) ..inline void KSV2DRG3 (HSVCOLOR *hsv , DRGBCOLOR * drgb) { color .h if (hsv->s==0.0) { drgb->r=drgb->g=drgb->b=hsv->v; } else { int i; double f,p,q,t,h; h = ( (hsv->h >= 360.0) ? hsv->h - 360.0 : hsv- > h) ; h/= 60.0; i= (int)h; f=h- (double) i; p=hsv->v* (1.0-hsv->s) ,- q=hsv->v* (1.0-(hsv->s* ) ) ; t=hsv->v* (l-(hsv->s* (1-f) ) ) ; switch (i) { case 0: drgb->r=hsv->v;drgb->g=t,-drgb->b=p; break; case 1: drgb->r=q;drgb->g=hsv->v,-drgb->b=p; break; case 2: drgb->r=p;drgb->g=hεv->v;drgb-:b=t ; break; case 3: drgb->r=p,-drgb->g=q;drgb->b=hsv->v; break; case 4: dxgb->r=t;drgb->g=p;cLrgb->b=hsv->v; break; case 5: drgb->r=hsv->v;drgb->g=p;drgb->b=q; break; } } inline COLORREF HSV2COLORREF (HSVCOLOR *c) { DRGBCOLOR drgb; HSV2DRGB (c , idrgb) ; return DRGB2COLORREF (&drgb) ; } _inline void COLORREF2HSV (COLORREF cr, HSVCOLOR *hsv) { DRGBCOLOR drgb; COLORREF2DRGB (cr, &drgb) ; DRGB2HSV(&drgb,h≤v) ; } »ifdef _CELLVUE_H_ ..inline void C0L0RREF2APS (COLORREF cr.APSCOLOR *aps) { *aps=* ( (APSCOLOR * ) &cr) ; } _inline COLORREF APS2COLORREF (APSCOLOR 'aps ) { return * ( ( COLORREF * ) aps ) ; } _inline APS2DRGB (APSCOLOR *aps , DRGBCOLOR *drgb) { drgb->r= (double ) (aps ->r) /255 . 0 ; color.h drgb->g= (double) (aps->g) /255.0; drgb->b= (double) (aps->b) /255.0; .inline DRGB2APS (DRGBCOLOR *drgb,APSCOLOR *aps) aps->r = (int) ( (drgb->r*255.0) +0.5) ; aps->g = (int) ( (drgb->g*255.0) +0.5) ; aps->b = (int) ( (drgb->b* 255.0) +0.5) ,- .inline void HSV2APS (HSVCOLOR *hsv, APSCOLOR *aps) { DRGBCOLOR drgb; HSV2DRGB (hsv, idrgb) ; DRGB2APS (&drgb, ps) ; _inline void APS2HSV(APSCOLOR * ps , HSVCOLOR *hsv) { DRGBCOLOR drgb; APS2DRGB (aps , _drgb) ; DRGB2HSV(&drgb, hsv) ; } #endif / /_CELLVUE_H_ #endif //_COLOR_H_ /*** End of file: color.h ***/ f ad p .bar . c static char fadebar_id[] '$Id: fadebar.c.v 1.2 1998/12/16 02:10:10 b enn Exp S " ; - include <windows . h> - include <windowsx.h> # include "fadebar.h" #include "color. " _inline COLORREF FadeRGBColo ( int w,int x, COLORREF cl, COLORREF c2) { double frac= (double) / (double) ; double if rαc=l .0-frac ; int r , g , ; r= (int) (frac* (double) GetRValue (c2) +ifrac* (double) GetRValue (cl) +0.5) g= (int) (frac* (double) GetGValue (c2) +ifrac* (double) GetGValue (cl) +0.5! b= (int) (frac* (double) GetBValue (c2) +ifrac* (double) GβtBValue (cl) +0.5) return RGB(r,g,b) ; .inline COLORREF FadeHSVColor (int w,int x, HSVCOLOR *cl,HSVCOLOR *c2) { double frac= (double) x/ (double) w; double if rac=l.0-frac ; HSVCOLOR t; .h=ιrac*c2->h+ifrac*cl->h; . s=f rac*c2->s+ifrac*cl->ε ; t .v=frac*c2->v+ifrac*cl->v; return HSV2 COLORREF (&t) ; fadebar . c typedef s ruct ( COLORREF leftRGBColor; COLORREF rightRGBColor; HS V COLOR lef HSVColor; HSVCOLOR rightHSVColor; int mode, w, h; HDC hdc ; } FadeBarState ; LRESULT CALLBACK FadeBarProc (HWND hWnd , UINT uMsg , WPARAM wParam LPAR AM IParam) { FadeBarState * fbs = ( FadeBarS tate * ) GetWindowLong (hWnd , GWL_USE RDATA) ; switch ( uMsg ) { case WM_SHOWWINDO : i f ( fbs&& ! fbs->w ) { RECT winRect; / 1 save our window dimensions for use later. //we don't have to worry about resizing - the tab dialogs are const size. GetWindowRect (hWnd, iwinRect) ; fbs->w=winRect . right-winRect . left ; fbs->h=winRec .bottom-winRec . top; //the window class style for the fade bar spec ifies //OWDC - that is a DC is allocated for each i nstance //you only have to get the dc once as soon as it is valid and //release it once when you are done with the w indow //saves all that Get/Release DC'ing during pai nting fbs->hdc=GetDC(hWnd) ; > return Def indowProc (hWnd, uMsg, Param, IParam) ; case WM_CREATE: fbs - (FadeBarState * )malloc (sizeof ( *fbs) ) ; memset (fbs, 0, sizeof (*fbs) ) ; fbs->mode = FBM_RGB; fbs- > leftRGBColor = RGB (255 , 255 , 255) ; fbs->rightRGBColor = RGB (255 , 0 , 255) ; fbs->le tHSVColor.h = 0.0; fbs->leftHSVColor.s = 1.0; fadebar . c fbs->leftHSVColor.v = 1.0; fbs->rightHSVColor . h=359.0; fbs->rightHSVColor . s=l .0 ; fbs->rightHSVColor.v=l.0; SetWindowLong(hWnd,GWL_UΞERDATA, (long) fbs) ; return DefWindowProc (hWnd. uMsg, wParam, IParam) ; case WM_DESTROY: //we are done with the dc for good now. ReleaseDC (hWnd, fbs->hdc) ; free (fbs) ; return DefWindowProc (hWnd,uMsg, wParam, IParam) ,- case WM_PAINT: ( int x; COLORREF curColor; //create a pen of the left-end color of the ba r //select it in and save the old pen (to restor e later) HPEN oldPen = (HPEN) SelectObject(fbs->hdc, CreatePen (PS_≤ 0LID.1, fbs->mode==FBM_RGB?fbs->leftRGBCθlor:HSV2COLORREF! _ (fbs->leftHSVColor) ))); //draw the first vertical line of the bar MoveToEx ( fbs->hdc ,0,0, ULL) ; LineTo (fbs->hdc, 0, fbs->h) ; //loop through the rest of the lines for (x=l;x<fbs->w;x++) { curColor = fbε->mode==FBM_RGB ? F adeRGBColor (fbs->w,x, fbs->leftRGBColor, fbs->rightRGBColor) -. FadeHSVColor (fbs->w,x,& ; (fbs->leftHSVColor) , _ (fbs->rightHSVColor) ) ; //when we select the next pen we creat e, we //get back the handle of the last one we created/selected...delete it DeleteObjec ( //select a new pen for the nex t vertical line SelectObject (fbs->hdc, //create a pen of the appropriately blended color for the next fadebar . c v-line -£Js o lid— sofe— ashed-r— p- en with a width of 1 pixel CreatePen ( PS_SOLID , 1 , / /do a weighte d blend of the left _ right color- based on JUΓ x pos curColor) ) ) ; //move tc the top of our current v-lin e MoveToEx(fbs->hdc,x, O.NULL) ; //draw our current v-line to the botto m LineTo (fbs->hdc,x, fbs->h) ; //restore the old per and delete the last //pen we created (as returned from selectobjec t()) DeleteObjec (SelectObject (fbs->hdc , oldPen) ) ; //let windows know that we actually did redraw ValidateRect (hWnd.NULL) ,- } brea ; case WM_FBSETLC0L0R: if(fbs->mode == FBM_RGB) fbs->leftRGBColor = (COLORREF) IPa am; else if(fbs->mode == FBM_HSV && IParam) memcpy (& (fbs->leftHSVColor) , (void *) IParam, siz eof (HSVCOLOR) ) ; break; case WM_FBSETRCOL0R: if(fbs->mode == FBM_RGB) fbs->rightRGBColor = (COLORREF) IParam; else if (fbs->mode == FBM_HSV __ IParam) memcp (& (fbs->rightHSVColor) , (void *)lParam,si zeof (HSVCOLOR) ) ; break; case WM_FBGETLCOLOR: if ( '. IParam) break; if(fbs->mode == FBM_RGB) *( (COLORREF *) IParam) = fbs->lef RGBColor; else if(fbs->mode == FBM_HSV) memcpy ( (void * ) IParam, _ (fbs->leftHSVColor) , siz eof (HSVCOLOR) ) ; break; case WM_FBGETRC0LOR: if ( ! IParam) fadeba . c break; if (fbs->mode -= FBM RGB) *( ( COLORREF *) IParam) = fbs->rightRGBColor• else if(fbε->mode == FBM_HSV) zeof (HSVCOLOR ) ) ; ^"^ '^ * J 1Param ' & ^^->rightHSVColor) , si break; case WM_FBSETMODE : fbs->mode = IParam; if (fbs->mode! =FBM_HSV __ fbs->mσde! =FBM_RGB) fbs->mode = FBM_INACTIVE; break; default: return DefWindowProc (hWnd, uMsg, Param, IParam) ; return 0 ,- BOOL RegisterFadeBar (HINSTANCE hlnstance) { WNDCLASSEX wc ; //ream it clean memse (twc, 0 , sizeof (wc) ) ; //set the few necessary members //always and everywhere... wc.cbSize = sizeo (wc) ; //the message handler wc . lp WndProc = FadeBarProc ; //window class name wc.lpszClassName = FadeBarClassName; //we don't have to worry about h or v redraws //alloc a DC for each instance and keep it until destruction //saves on all the Get/Release DC BS during painting wc. style = CS_OWNDC; //set the instance wc.hlnstance = hlnstance; if (RegisterClasεEx (iwc) ) return TRUE; return FALSE; fadebar .c void UnRegiεterFadeBar (HINSTANCE hlnstance) Unr egister lass (FadeBarClassName, hlnst nc e ) fadebar . h #ifndef _FADEBAR_ H _ #define _FADEBAR_H_ #define WM_FBSETLCOLOR WM_USER+1 *define WM-.FBSETRCOLOR WM_FBSETLCOLOR+l #define WM_FBGETLCOLOR WM_FBSETRCOLO R+ 1 tfdefine WM ^ FBGETRCOLOR WM_FBGETLCO L OR+1 #define WM_FBSETMODE WM_FBGETRCOLOR+1 #define FBM_INACTTVE 0 #define FBM_RGB 1 #define FBM_HSV 2 i d efine FadeBarClassName "WCFade B ar" #ifdef cplusplus extern "C" { #endif // cplusplus B O OL RegisterFadeBar (HINSTANCE hlnstance ); void UnRegisterFadeBar (HINSTANCE hlnstance ); #ifdef cplusplus } #endif // cplusplus #endif / /_FADEBAR_H_ / * - * End of file: fadebar. * * * / cellvue . h iifn.ef _CELLVUE_H_ #define _CELLVUE_H_ #ifdef cplusplus extern "C" { #endif // import/export macro so both cellvue and plugins // can include the same .h files #ifndef APSAPI - ifdef COMPILING_CΞLLVUE_APP #define APSAPI declspec (dllexport) #else #define APSAPI declspec (dllimport) #endif #endif ********/ // messages - valid range is WM_USER (1024) to 32768 enu _APSWMENUMS { WM_APS_INIT = WM_US£R + 5001, // sent to all plugin main message handlers just after load WM_AFS_CONSTRUCTO , // tell plugin to create an instance WM_AFS_NEW_DATASET_LOADED, // sent to all plugin *instances* when a new dataset is opened WM_APS_REQUEST_CUBE, cellvue. h // request 3d cube WM_APS_CUBΞ_PACKET, // new cube data WM_APS_REQUEST_SLICE, // request a 2d slice WM_APS__S ICΞ_PACKE , // new slice WM_APS_SET_ANTS_X, // sent to all plugin *instances* when crop region changes so they can up date their own views WM_APS_SΞT_ANTS_Y, // " WM_APS_SET_ANTS_Z , // " WM_APS_CANCΞL_LOAD, // sent to all plugins from input plugin when load fails WM_AFS_BRIGHTFIELD_MODE, //sent to all plugins when going to/from brightfield mode WM__APS_CMDLINE, //sent to all plugins if there is a command line to share WM_APS_SΞT_ANTS_3D_ , // sent from 2d to 3d plugin when the ants region changes WM_APS_ΞET_ANTS_3D_Y, // " WM_APS_SET_ANTS_3D_Z, // " WM_APS_REDRAW_3D, // force 3d plugin to re-render M_APS_DISABLE_ANTΞ_DRAGGING, // ' tell 2d win to not let user drag ants WM-_APS_ENABLE_ANTS_DRAGGING, // let user drag ants again WM_APS_CONFINE_ANTS_ , // message from 3d -> 2d to confine ants region WM_APS_CONFINE_ANTS_Y. WM_APS_CONFINE_ANTS_Z , WM_APS_TAB_LOSE_FOCUS, // sent to a tab dialog proc when user selects new tab cellvue. h WM_APS_TAB_GAIN_FOCUS , WM_APS_GETDSVARVAL, //sent only to input plugin - lookup the //value associated w/ a var (WPARAM) from the //dataset string table, the const char * is returned //in a char ** (LPARAM) }; // keyboard accelerator messages (look in cellvue. re) ftdefine IDM_FULLSCREEN 1 ^define IDM_SHOWPLUGINS 2 // defines // fixed point math typedef unsigned long FIXEDPOINT; #define FIXEDPLACES 14 // number of places that wi 11 be used for the "remainder" portion (was 15) #define FIXEDPOWER ( 1«FIXEDPLACEΞ ) #define FIXEDRMDMASK ( (1«FIXEDPLACES) - 1 ) #define INT2FIXED (a) ( ((unsigned long) (a) ) <<FIXEDP LACES ) #define FLOAT2FIXED (a) ( (unsigned long) ( ( (double) (a) ) * ( (dou ble) FIXEDPOWER) ) ) *define FIXEDMULINT (a, b) ( (a)*(b) ) #define FIXEDMUL (a, b) ( ((a) Mb)) » FIXEDPLACES ) #define FIXEDRMD (a) ( (a) _ FIXEDRMDMASK ) . define FIXED2INT(a) ( (a) >> FIXEDPLACES ) tdefine FIXED2FLOAT(a) ( ( (double) (a) ) / ((double) FIX EDPOWER) ) #def ine FIXED2IDX ( a , bits l ( ( (a) >> (FIXEDPLACES- (bits) ) ) _ ( (l«(bits) )-l) ) // put tabs on top instead of bottom #define TABS ON TOP // min color depth required #define MIN COLOR DEPTH 15 // minimum window size for main window cellvue. h fldefine MIN_APP_WIDTH 1024 #define MIN_APP_HEIGHT 768 // hardcoded size of the 3d window ^define _2D_VIEW_W 362 #define _3D_viEW_H 362 // id of any tab control idefine IDC ^ APSTABCTL 4096 // flags for APSCUBE's RGBFlags #define RGBFLAGS_RED 0x0001 #define RGBFLAGS_GREEN 0x0002 #define RGBFLAGS_BLUE 0x0004 #define RGBFLAGS_AUX 0x0008 #define CUBE_8BIT_COLOR 0x0010 //cube is 8 bit paletted color volume #define CUBE_16BIT_C0L0R 0x0020 //cube is 16 rgb bit color volu me (4 bits x rgba?) #define CUBE_2 BIT__COLOR 0x0040 //cube is 24 rgb bit color volu me ^define CUBE_32BIT_COLOR 0x0080 //cube is rgba color volume //barring any of above, cube is 8 bit mono volume // plugin flags tdefine PLUGFLAGS_LUT_CONVERTED 0x0001 // internal used only by apslut #define PLUGFLAGS_ENHANCED 0X0002 // internal used only by apsenh // structures // color struct (for Win32) typedef struct _APSCOLOR { BYTE b; BYTE g ; BYTE r; BYTE a ; // not used } APSCOLOR, *LPAPSCOLOR; // slice request/return structure cellvu . h typedef struct _APSSLICE DWORD dwPacketlD; CHAR cAxis; // par am 'y', 'z' LONG dwDepth; // par am LONG xl, yl, x2, y2; / / ex-params DWORD dwWidth; DWORD dwHeight; DWORD dwChannels ; DWORD dwRGBFlags ; DWORD dwBitsPerPixel; DWORD dwFlagε ; BITMAPINFO b i; // windows bitmap info (why not have it here too, eh?) DWORD channel_masks_dummy [2] ; // needed for b&w -- do no : remove order ! LPAPSCOLOR psData; DWORD dwReservedl DWORD dwReserved2 DWORD dwReserved3 } APSSLICE, *LPAPSSLICE; // generic "cube" structure used to pass 3D requests and returns typedef struct _APSCUBE { DWORD dwPacketID; DWORD dwRefCoun ; // reference count DWORD xl, yl, zl; // param (all 0 ' s to specify full dataset) DWORD χ2, y2, z2; // param (all 0's to specify full dataset) double rmult, gmult, bmult; // param (channel math multipliers) DWORD dwFitlnCubeSize; // param (fit resultant voxels in a cube of n*n*n) DWORD dwSmpWidth, dwSmpHeight, dwSmpDepth; cellvue. h // dimensions of full smp file DWORD__ dwWidth, dwHeigh , dwDepth; // dimenasions of loaded cube data DWORD dwChannels ; // channels in the big file (not in the cube) DWORD dwStartZ, dwStopZ; / / new region that ' s ust been added DWORD dwFlags; LPBYTE pbVoxels ; // raw voxels LPBYTE pbPhongε ; // shaded surface LPBYTE pbSeg; // segmentation buffer APSCOLOR *psPalette; // color palette for 8 bit color volumes DWORD dwReservedl ; DWORD dwReserved2 ; DWORD dwReserved3 ; } APSCUBE, "LPAPSCUBE; /****** re****************,.************! ,********»****** ** * *********** ***** ** / / externs extern APSAPI DWORD dwExpired; extern APSAPI BYTE szAppPathU ; extern APSAPI BYTE szPluginPath [ ] ; extern APSAPI BYTE szDatasetPat [ ] ; extern APSA I BYTE szDatasetNamef] ; extern APSAPI HINSTANCE hAppInstance,- extern APSAPI HWND hAppWnd,- extern APSAPI HWND h2DWnd; extern APSAPI HWND h3DWnd; extern APSAPI HWND hϋtilWnd; extern HWND hRightSplitter; extern HWND hMainSplitter; cellvue. h extern HWND hBottomTabHolder ; extern HWND " hBottomTabCtrl; extern APSAPI BOOL dwRenderingHires ; extern APSAPI BOOL dwCloseAfterHires ; extern APSAPI DWORD dwDatasetWidth; extern APSAPI DWORD dwDatasetHeigh ,- extern APSAPI DWORD dwDatasetDepth; ****** * ****************** •• * » ************** * ***************** , *** ** ** * // prototypes // splash. c int SplashScreen( int time // expire. c int CheckExpire ( ) ; / / inviswnd. c HWND apsInvisCreateWindow( ) ; // 2dwnd.c HWND aps2DCreateWindow( ) ; / / 3dwnd. c HWND aps3DCreateWindow( ) ; / / utilwnd . c HWND apsUtilCreateWindow ( ) ; // dlghold.c HWND apsDlgHolderCreateWindow( ) ; // htabhold.c HWND apsHTabKolderCreateWindow( ) ; // vtabhold.c HWND apsVTabHolderCreateWindow( ) ; // router. c VOID InitRouting ( ) ; APSAPI VOID RequestOrthoSlice( CHAR cAxis, LONG dw Depth, HWND hlnstWnd ) ; APSAPI VOID RequestOrthoSliceEx( CHAR cAxis, LONG dwDepth, LONG xl , LONG yl, LONG x2, LONG y2 , HWND hlnstWnd ) ; APSAPI VOID ProduceOrthoSlice ( LPAPSSLICE psSlice, cellvue. h HWND hlnstWnd ) ,- APSAPI LPAPSSLICE- -Dupli-cateOrthoSlice( LPAPSSLICE εSl ice ); APSAPI VOID DestroyOrthoSlice( LPAPSSLICE psSlice APSAPI VOID RequestCubef LONG xl . LONG x2 , LONG yl, LONG y2, LONG zl, LONG z2 double r ult, double gmult, double bmult, LONG dwFitlnCubeSize, HWND hlnstWnd ) ; APSAPI VOID ProduceCube( LPAPSCUBE psCube, HWND hi nstWnd ) ; APSAPI VOID DestroyCube( LPAPSCUBE psCube ) ; APSAPI LONG RefIncCube( LPAPSCUBE psCube ); APSAPI LONG RefDecCube( LPAPSCUBE psCube ); APSAPI VOID SendMessageToAllPluginlnstances ( UINT Msg, WPARAM wParam, LPARAM IParam // apsmisc.c APSAPI LPBYTE apsmalloc( DWORD dwNumBytes ) ; APSAPI LPBYTE apsmallocO ( DWORD dwNumBytes ) ; APSAPI VOID apsfree( LPVOID pbMem ) ; APSAPI LPSTR StrSave( LPSTR szStringToCopy ); APSAPI LPSTR NameOnly( LPSTR szFileName ); APSAPI VOID Rect2Pos( LPRECT psRect ) ; APSAPI VOID RectFromPos ( LPRECT psRect, LPRECT psSource ) ; APSAPI VOID Pos2Rec ( LPRECT psRect ) ; APSAPI BOOL PosInRect( LONG xPos , LONG yPos , LPRECT psRect ); APSAPI BOOL SetWindowRect ( HWND hWnd, HWND hWndlnsertAfter . LPRECT psRect, UINT uFlags ) ; APSAPI VOID ClipRect( LPRECT psClientRec , LPRECT psParent Rect ) ; APSAPI VOID MergeRects ( LPRECT psRect, LPRECT psRectl, LPR ECT psRect2 ) ; APSAPI BOOL NormalizeRect ( LPRECT psRect ) ,- APSAPI VOID Zoom ec ( LPRECT psDest. LPRECT psSource, doub le fZoom ) ; APSAPI VOID UnzoomRect ( LPRECT psDest, LPRECT psSource, do uble fZoom ) ; APSAPI VOID StretchChildToFitParen ( HWND hParent ); APSAPI VOID StretchChildrenToFitParent ( HWND hParent ); APSAPI VOID D rawBitmaρ( HDC hdc, HBITMAP hBit ap, int xSta rt, int yStart ) ; APSAPI VOID winprintf ( HDC hdc, int x, int y, char *sz, ... ); APSAPI HWND create L istboxWindow( LPSTR szTitle, DWORD dwLe ft, DWORD dwTop DWORD dwWidth, DWORD dwHeigh , HWND hParent ) ; APSAPI VOID p rintfListbox( HWND hWnd, LPSTR szMeεsage, ... ); APSAPI VOID apsErrBox( LPSTR szMessage, ... ) ; APSAPI LPDWORD A lloc R GBD IB ( HDC* phdc, HBITMAP* phbmp, int w, int h, HDC usedc ) ; APSAPI VOID FreeRGBDIB( HDC* hdc, HBITMAP* hbmp ) ; cellvue. h APSAPI VOID CheckWiπdowεMessages ( ) ; . ifdef cplusplus } #endif #endif /*** End of file: cellvue.h ***/

Claims: 1. An image production method comprising: a) staining a sample with a fluorescent dye; b) producing a first image of the resultant fluorescent-dyed sample; and c) using a digital processor to convert said first image to a second image that mimics an image of said sample stained with a non-fluorescent dye. 2. The method of claim 1. wherein said first image is produced using a block-face microscope. 3. The method of claim 1, wherein said converting of said first image to said second image comprises applying a lookup table to said first image. 4. The method of claim 1, wherein said sample is stained with at least two fluorescent dyes. 5. The method ol claim 1. wherein said sample is a biological sample. 6. An image production method comprising: a) staining a sample with a first and a second fluorescent dye; b) producing a first image of said sample stained with said first dye and a second image of said sample stained with said second dye; and c) using a digital processor to convert said first and second images to a third image that mimics an image of said sample stained with hematoxylin and eosin. 7 The method ot claim 6, wherein said first and second images are produced using a block-face microscope. 8. An image production method compπsing: a) staining a sample with a fluorescent dye; b) producing a first image of said sample stained with said dye and a second image of said sample stained with said dye; and c) using a digital processor to convert said first and second images to a third image that mimics an image of said sample stained with hematoxylin and eosin. 9. The method of claim 8, wherein said first and second images are produced using a block-face microscope. 10. The method of claim 8, wherein said dye comprises a metachromatic dye. 1 1. The method of claim 10. wherein said metachromatic d\e comprises acridine orange. 12. An image production method comprising: a) staining a sample with said plurality of fluorescent dyes, b) producing a first image of one of said dyes in said sample, and c) using a digital processor to convert said first image to a second image that mimics an image of said sample stained with one non-fluorescent dye. 13. The method of claim 12, wherein said first image is produced using a block-face microscope. 14. An image production method comprising: a) staining said sample with said plurality of fluorescent dyes having overlapping excitation and emission spectra: b) producing a first image that mimics said sample stained with a subset of said plurality of fluorescent dyes; and c) using a digital processor to convert said first image to a second image that mimics an image of said sample stained with at least one non- fluorescent dye. 15. The method of claim 14, wherein said first image is produced using a block-face microscope.

Inventors: HENDRICKSON ANDREW, HERRERA BENN P, KERSCHMANN RUSSELL L, HENDRICKSON, ANDREW, HERRERA, BENN, P., KERSCHMANN, RUSSELL, L.
Applicants: RESOLUTION SCIENCES CORP, RESOLUTION SCIENCES CORPORATION
Application year: 2000
Main classification: G06K9
IPC codes: G01N1, G01N33, G06T5