Login| Sign Up| Help| Contact|

Patent Searching and Data


Title:
TRANSFORMATION OF DIGITAL IMAGES
Document Type and Number:
WIPO Patent Application WO/2000/070541
Kind Code:
A1
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.

Inventors:
KERSCHMANN RUSSELL L
HENDRICKSON ANDREW
HERRERA BENN P
Application Number:
PCT/US2000/012960
Publication Date:
November 23, 2000
Filing Date:
May 12, 2000
Export Citation:
Click for automatic bibliography generation   Help
Assignee:
RESOLUTION SCIENCES CORP (US)
International Classes:
G01N1/28; G01N33/48; G01N1/30; G01N33/58; G06T5/50; (IPC1-7): G06K9/00
Foreign References:
US4202037A1980-05-06
US5986271A1999-11-16
US4794460A1988-12-27
US5854710A1998-12-29
Attorney, Agent or Firm:
Clark, Paul T. (LLP 176 Federal Street Boston, MA, US)
Download PDF:
Claims:
APPENDIX<BR> static char apsstain_id(l = 'sid: apsstain.cpp,v 1.7 1999/04/29 21:35:44 benn Exp $";<BR> &num include <windows.h><BR> &num include <stdio.h><BR> &num include <string.h><BR> &num include "cellvue.h"<BR> &num include "color.h"<BR> &num include "apsstain.h"<BR> &num include "apsini.h"<BR> inline BYTE InvertColor (BYTE mono) {<BR> return 255 - mono;<BR> }<BR> inline APSCLR InvertColor (APSCLR c1) (<BR> return RGBCLR (InvertColor (RGBRED(c1),<BR> InvertColor (RGBGREEN(c1)),<BR> InvertColor (RGBBLUE(c1)));<BR> }<BR> inline APSCLR RotateColor (APSCLR c1) {<BR> return RBBCLR (RGBBLUE(c1),RGBRED(c1),RGBGREEN(c1));<BR> }<BR> inline BYTE MaxChroma (APSCLR c) {<BR> return MAX (MAX (RGBRED(c),RGBGREEN(c)),RGBBLUE(c));<BR> }<BR> inline APSCLR AddColors (APSCLR c1, BYTE mono) {<BR> return RGBCLR(<BR> MIN (RGBRED (c1) +mono, 255),<BR> MIN (RGBGREEN (c1) +mono, 255),<BR> MIN (RGBBLUE (c1) +mono, 255));<BR> }<BR> inline APSCLR AddColors (APSCLR c1, APSCLR c2) {<BR> return RGBCLR (<BR> MIN (RGBRED (c1) +RGBRED (c2), 255),<BR> MIN (RGBGREEN (c1) +RGBGREEN (c2), 255),<BR> MIN (RGBBLUE (c1) +RGBBLUE (c2), 255)); inline APSCLR AddColors (APSCLR c1, APSCLR c2, BYTE mono) (<BR> return RGBCLR (<BR> MIN (RGBRED (c1) +RGBRED (c2) +mono, 255),<BR> MIN (RGBGREEN (c1) +RGBGREEN (c2) +mono, 255),<BR> MIN (RGBBLUE (c1) +RGBBLUE (c2) +mono, 255));<BR> }<BR> inline APSCLR AddColors (APSCLR c1, APSCLR c2, APSCLR c3) (<BR> return RGBCLR (<BR> MIN (RGBRED (c1) +RGBRED (c2) +RGBRED 9c3), 255),<BR> MIN (RGBGREEN (c1) +RGBGREEN (c2) +RGBGREEN (c3), 255),<BR> MIN (RGBBLUE (c1) +RGBBLUE (c2) +RCBBLUE (c3), 255));<BR> }<BR> inline APSCLR AddColors 9APSCLR c1, APSCLR c2, APSCLR c3, APSCLR c4) (<BR> return RGBCLR<BR> MIN (RGBRED (c1) +RGBRED (c2) +RGBRED (c3) +RGBRED (c4), 255),<BR> MIN (RGBGREEN (c1) +RGBGREEN (c2) +RGBGREEN (c3) +RGBGREEN(c4), 255),<BR> MIN (RGBBLUE (c1) +RGBBLUE (c2) +RGBBLUE (c3) +RGBBLUE (c4), 255));<BR> }<BR> /*<BR> OverlayColors does does subtractive colorspace color adding conceptually : rgbl->cmyl rgb2->çmy2, cmylxcmy'->cnlyl, cmy3->rgbotlt rgb-> crny is simply c = 1.0-r, m = 1.0-g, y = 1 0-b crnyback to rgb is, of course : r _ 1. 0-c, g = 1. 0-m, b = 1. 0-y so for eech channel of rgbl & rgb2 to do a subtractive colorspace add we are doing the following : out = 1. 0- ( 0-inl) + (1. 0-in2)) doing the algebra we get : out = 1.0- (2. 0-inl-in2) out = 1.0-2.0 + inl + in2 out = inl + in2-1.0 so going to 0-255 chrominance space from normalized chrominance space and adding bounds checking, we get: out = MAX (O, inl+in2-255) additional channels, of course, work the same way, but with the algebra appropriate to the number of colors being added. for 3 colors we end up with: out = inl + in2 + in3-2. 0 out = MAX (O, inl+in2+in3-510) for 4 colors we have : out = inl + in2 + in3 + in4-3. 0 out_ MAX (O, inl+in2+in3 «-in4-765) '/ inline BYTE SubtractiveAdd (BYTE cl, BYTE c2) ( return MAX (cl+c2-255, 0) ; } inline BYTE SubcractiveAdd (BYTE cl, BYTE c2, BYTE c3) { return MAX (cl+c2+c3-510, 0) ; ) inline BYTE SubtractiveAdd (BYTE cl, BYE c2, BYTE c3, BYTE c4) ( return MAX (cl+c2+c3+c4-765, 0) ; inline APSCLR OVerlayColors (APSCLR cl, APSCLR o2) ( //this is what we are doing conceptually //return InvertColor (AddColors (InvertColor (cl), Invertcolor (c2))) ; //this is the optimized algebraic distillation returnRGBCLR ( SubtractiveAdd (RGBRED (cl), RGBRED (c2)), SubtractzveAdd (RGBGRE (cl), RGBGREEN (c2)), subtractiveAdd (RGBBLUE (cl), RGBBLUE (c2))) ; ) inline APSCLR OverlayColors (APSCL cl, APSCLR a2, APSCLR c3) ( //this is what we are doing conceptually //return InvPrtColor (AddColors (Intertcolor (cS verr¢ozor (o2) lnvertcolQr (C3))) ; //this is the optimized algebraic distillation returnRGBCLR ( SubtractiveAdd (RGBRED (cl), RGBRED (c : 2), RGPRBD (c3)), SubtractiveAdd (RGBGREEN (cl), RGBGREEN (c2), RGGRFEN (c3)), SuhtractiveAdd (RGSSLUE (c1), RGBBLUElc2), RrUg (G3))) ; inline APSCLR OverlayColors (APSCLR cl, APSCLR c2, APSCLR c3, APSCLR c4) ( //this is what we are doing conceptually //return InvertColor (AddColors (Invertcolor (a7.), TnvPrtColor (c2), Inverr. ror (C3), InvertColpx (C4))) //this is the opcimized algebraic distillation returnRGBCLR ( SubcraotiveAdd (RGBRED (cl). RC ; BRH) ? (c2), RGBRED (c ; i), RGBRED (c)), SubtractiveAdd (RGBGRBEN (cl), RGBGREEM (e2). RGm ! REEN (e3), RGBGRBEM (c)), SubtracciveAdd (RGBBLUE (el), RG ! 6SLUE<c2), RGBBLUEfc3). RGBBLUE (c4))) ; inlineAPSCLR USV2APS (HSVCOLOR thsv) f DRGBCOLOR drgb ; HSV2DRGB(hs\t, &drgl ;) reeurn RGBCk ((BYTE) (255. O*dRgb. r), (8YTE) (255. 0Adrgb. g} YTi) (255. 0>drgb. bJ) I classCHSVCOLOR f public ; HSVCOLOR m_Color ; inline CHSVCOLOR (double h, double s, double vl f m_Color. s = s m Color. = g ; m Colox, p- ) inline operator HSVCOLOR (void) f return n) Color ; ; ) ; CApsLUt sLUT ; CApsLUT () ( memsetfthis, 0, sLzeof (*this 1 CApsLUT : : ~CApsLUT () { J voicl CAPSLUT:: Build (HSVCOLOR firstcolor liSVCOLOR lastcolor, int firgtldx/*=O*/, int lascld_%/vm2SS*/) Gotb. e) (lastZcx-first=dx) ; do'uble rllri c c'Lc/_255/) doubledh = lastColor. h-firatcolor. h- double ds = lascColor. s-firstColor.s; doubledv = lascColor. v-firstColor. vt int i = lascldx-li APSCLR *entries = Entries () ; HSVCOLOR curcolor ; double fetr ; entriesffirscldx] = HSV2APS (&firscColor) ; encriesrlastldx] = HSV2APS (&lastColor) ; do{ fatr = (double) i/run ; curcolor. h = firætColor h + fctrwdh- curColor. s = firstColox. s + fatrds : curColor. v = firstColor. v + fctr*dv entries [i] = HSV2APs (&curColor) ; ) while (z>firstrdx) ; ? CApSStairi : : cApBstain () ( memsetfthis, 0, sizeof twth's)) ; } CApsStain:: CApsSain (cons& char" : Mtato, HSVCOLOR deEColor. ine. hueMin, inb hueMax) ( memsec (this, 0, sizeof (*this)) ; Name (name) ; DefaultColor (defColor) ; UserDefaultColor(defColor) ; HueMin (hueMin) ; HueMax(hueMax) ; CurrentColor (defcolor) ; ) CApsStain : : CApsStain (consL char *name, HSVCOLOR defColo, r" i. nt hueMin, int hueMax, HSVCOLOR xOverColor, in t xOverVal, BOOL xorerFade) t memset (this, 0, sizeof (*this)) ; Name(name) ; DefaulTcolordefcolor) UserDefaulccolor(defColor) ; HueMin (hueMin) ; HueMax(hueMax) ; CurrentColorfdefColor)- XOverColor(xOverColor) ; XOverVal (xoverval) ; Z§OverFade (xoverFade) CApsStain:;-CApsStain () { } //tacio CApsSEain Hema. c. oxylin ("Hnmat : oxylin'', CllGVCOljOH (240. 0, 0. 9, 0. 8), 200, 275) ; //st&bic CApsStain RosinC'Eosin", CHSVCO. !.. OR (332. 0. 0.85,0. 84), 310, 3fl5); 3 static CApsStain Hematoxylin ("Hematoxylin", CHSVCOLOR (241.0,0.64,1.0),190,285);<BR> static CApsStain Eosin ("Eosin", CHSVCOLOR (323.0,.0,1.0),300,395);<BR> static CApsStain TBlue ("Toluidine Blue", CHSVCOLOR (234.0,0.53,0.85), 205, 250);<BR> static CApsStain FRed ("Fast Red", CHSVCOLOR (0,0.85,0.90), 310, 385);<BR> static CApsStain DFStain1 ("DFStain1", CHSVCOLOR (0.0, 1.0, 1.0), 310, 385);<BR> static CApsStain DFStain2 ("DFStain2", CHSVCOLOR (120.0, 1.0, 1.0), 90, 150);<BR> static CApsStain DFFree1 ("DF Free 1", CHSVCOLOR (0.0, 1.0, 1.0), 0, 359);<BR> static CApsStain DFFree2 ("DF Free 2", CHSVCOLOR (120.0, 1.0, 1.0), 0, 359);<BR> static CApsStain DFFree3 ("DF Free 3", CHSVCOLOR (240.0, 1.0, 1.0), 0, 359);<BR> static CApsStain DFFree4 ("DF Free 4", CHSVCOLOR (300.0, 1.0, 1.0), 0, 359);<BR> static CApsStain BFFree1 ("BF Free 1", CHSVCOLOR (240.0, 0.9, 0.8), 0, 359);<BR> static CApsStain BFFree2 ("BF Free 2", CHSVCOLOR (322.0, 0.85, 0.84), 0, 359);<BR> static CApsStain BFFree3 ("BF Free 3", CHSVCOLOR (120.0, 10, 1.0), 0, 359);<BR> static CApsStain BFFree4 ("BF Free 4", CHSVCOLOR (300.0, 1.0, 1.0), 0, 359);<BR> static CApsStain EVG ("EVG", CHSVCOLOR (240.0, 0.31, 0.82), 230, 250, CHSVCOLOR (240.0, 0.0, 0.0), 127,<BR> FALSE);<BR> static CApsStain EVGCounter ("EVG Counter", CHSVCOLOR (360.0, 0.9, 0.83), 340, 380);<BR> CApsStainSet HandF ("Hematoxylin & Eosin", 2, TRUE, &Hematoxylin, &Eosin);<BR> CApsStainSet TolBlue ("Toluidine Blue", 1, TRUE, &TBlue);<BR> CApsStainSet FastRed ("Fast Red", 1, TRUE, &FRed);<BR> CApsStainSet DFDual ("Dual DF Stain Set.", 2, FALSE, &DFStain1, &DFStain2);<BR> CApsStainSet DFMono ("Mono DF Stain Set", 1, FALSE, &DFStain1);<BR> CApsStainSet ApsDFRaw ("Aps Raw");<BR> CApsStainSet DFFree ("DF Free",4,FALSE,&DFFree1,&DFFree2,&DFFree3,&DFFree4);<BR> CApsStainSet BFFree ("BF Free",4,TRUE,&BFFree1,&BFFree2,&BFFree3,&BFFree4);<BR> CApsStainSet SFGEVG ("SFG EVG", 2, TRUE, &EVG, &EVGCounter); CApsSzainSet *StainiSets [] = i &HandE, &TolBlue, &yastRA-do #ifndef OUTSIDE_RELEASE &SFGEVG, &DFDual, &DFMono, aDFFree, &BFFree, #endi//OUTSIDE ja. BLE. SE &A, psDFRav, NULL int NumSwainSews = sizeof (StainSet3)/sizeof (ScainSetst0])-li C, gStainse xFiadstainset (conec c'ar 'name) ( CApsSLai. riSeL **jsveC = StainSets ; while (ssVec) ( ijEUsc. ricmptname, (*ssVee)->Name ())) return *ssVec ; ssVec++; ? recurs NULL : I static eApsLuG srainUlTS (MAXSTAINS] ; voidCApsSrainSer : : RESoreDefaultColors () int ns = NumStains () i CApsStain *scain ; fOx (1riC s=O : s<as : s*1 stain = Stain (s) : scain->CurrentColor (stai. a->DefaulGColor ()) ) ) void CApsStainSet::RestoreUserDefaul(Colors() (<BR> int ns = NumStains();<BR> CApsStain *stain;<BR> for (int s=0;s<nss++) {<BR> stain = Stain(s);<BR> stain->CurrentColor (stain->UserDefaultColor());<BR> }<BR> }<BR> BOOL CApsStainSet::SaveUserDefaultColors (void) (<BR> int ns = NumStains ()-1;<BR> CApsStain *stain;<BR> HSVCOLOR clr;<BR> if (!IniSetSection ("Stains",TRUE))<BR> return FALSE;<BR> if (ns<0)<BR> return FALSE;<BR> do (<BR> stain = Stain (ns);<BR> clr = stain->CurrentColor();<BR> stain->UserDefaultColor(clr);<BR> if (!IniSetHSV((char *)stain->Name(),clr.h,clr.s,clr.v))<BR> return FALSE;<BR> } while (ns--);<BR> return TRUE;<BR> }<BR> BOOL CApsStainSet::LoadUserDefaultColors (void) (<BR> CApsStain *stain;<BR> int ns;<BR> double h, s, v;<BR> BOOl rv = FALSE;<BR> if (!IniS@tSeotion ("Stains",FALSE))<BR> return rv; if ((ns = NumStains())) {<BR> ns--;<BR> do {<BR> stain = Stain (ns);<BR> if (IniGeLHSV((char *) stain->Name(),&h,&s,&v)) {<BR> stain->UserDefaultColor (CHSVCOLOR (h,s,v));<BR> stain->CurrentColor (stain->UserDefaultColor());<BR> rv = TRUE;<BR> }<BR> } while (ns--);<BR> }<BR> return rv;<BR> }<BR> void CApsStainSet::BuildLUTS (int stainidx/*=-1*/) (<BR> HSVCOLOR noStain;<BR> HSVCOLOR stainColor;<BR> CApsStain *stain;<BR> CApsLUT *lut;<BR> if (stainIdx<0) {<BR> int ns = NumStains ()-1;<BR> do {<BR> stain = Stain (ns);<BR> lut = & (StainLUTS [ns]);<BR> stainColor = stain->CurrentColor();<BR> noStain.h = stainColor.h;<BR> //NASTY HACK ALERT - h & e chook (special treatment)<BR> if (BrightField()/*&& (this ! =&HandE)*/) (<BR> noStain.s = 0.0;<BR> noStain.v = 1.0;<BR> } else {<BR> noStain.s = stainColor.s;<BR> noStain.v = 0.0;<BR> } if (stain->XOverVal()) {<BR> lut->Build(noStain,stainColor,0,stain->XOverVal());<BR> if (stain->XOverFade()) {<BR> lut#>Build (stainColor,stain->XOverCloro(),stain->XOverVal()+1,255);<BR> } else {<BR> lut->Build(stain->XOverColor(),stain->XOverColor(),stain#>XOverVal ()+1,255);<BR> }<BR> } else {<BR> lut->Build(noStain,stainColor);<BR> }<BR> } while(ns--);<BR> ) else {<BR> stain = Stain(stainIdx);<BR> lut = &(StainLUTS(stainIdx]);<BR> stainColor = stain->CurrentColor();<BR> noStain.h = stainColor.h;<BR> //NASTY HACK ALERT - h & e check (special treatment)<BR> if (BrightField()/&&(this!=&HandE)*/) {<BR> noStain.s = 0.0;<BR> noStain.v = 1.0;<BR> } else (<BR> hoStain.s = stainColor.s;<BR> noStain.v = 0.0;<BR> }<BR> if (stain->XOverVal()) {<BR> lut->Build(noStain,stainColor,0,stain->XOverVal());<BR> if (stain->XOverFade()) (<BR> lut->Build(stainColor,stain->XOverColor(),stain->XOverVal()+1,255);<BR> } else {<BR> lut->Build(stain->XOverColor(),stain->XOverColor(),stain->XOverVal()+1,255);<BR> }<BR> } else {<BR> lut->Build(noStain,stainColor);<BR> }<BR> }<BR> } void CApsStainSet::StainBuffer(APSCLR *src,APSCLR *dst,int pix,int channels) {<BR> if (!src#&num dst)<BR> return;<BR> pix--;<BR> //<BR> //NASTY HACK ALERT!!<BR> //<BR> //if (this==&HandE) {<BR> // BYTE *sb = (BYTE *) (src+pix);<BR> // int s1 = StainSrc(0);<BR> // int s2 = StainSrc(1);<BR> // CApsLUT *lut1 = &(StainLUTS[0]);<BR> // CApsLUT *lut2 = &(StainLUTS[1]);<BR> // BYTE black;<BR> // do {<BR> // back = InvertColor((BYTE)MAX(sb(s1),sb[s2]));<BR> // bst[pix] = AddColors(lut1->Lookup (sb[s1]),lut2->Lookup (sb[s2]),black);<BR> // sb -= sizeof (APSCLR);<BR> // } while (pix--);<BR> // return;<BR> //}<BR> switch (MIN (channels,NumStains())) {<BR> case 0:<BR> {<BR> if (BrightField()) {<BR> do {<BR> dst [pix] = InvertColor(src(pix));<BR> } while (pix--);<BR> ] else if (src!=dst) {<BR> do {<BR> dst [pix] = RotateColor (srco[pix]): } while (pix--);<BR> //memcpy (dst,src, (pix+1) *sizeof (APSCLR));<BR> }<BR> }<BR> break;<BR> case 1:<BR> {<BR> BYTE *sb = ((BYTE *) (src+pix));<BR> int s1 = StainSrc(0);<BR> CApsLUT *lut = & (StainLUTS(0));<BR> do {<BR> dst [pix] = lut->Lookup (sb[s1]);<BR> sb -= sizeof (APSCLR);<BR> } while (pix--);<BR> }<BR> break;<BR> case 2:<BR> (<BR> BYTE *sb = (BYTE *) (src+pix);<BR> int s1 = StainSrc(0);<BR> int s2 = StainSrc(1);<BR> CApsLUT *lut1 = &(StainLUTS[0]);<BR> CApsLUT *lut2 = &(StainLUTS[1]);<BR> if (BrightField()) {<BR> do {<BR> dst [pix] = OverlayColors(lut1->Lookup (sb[s1]),lut2->Lookup (sb[s2]));<BR> sb -= sizeof (APSCLR);<BR> } while (pix--);<BR> ) else {<BR> do {<BR> dst [pix] = AddColors (lut1->Lookup (sb[s1]),lut2->Lookup (sb[s2]));<BR> sb -= sizeof (APSCLR);<BR> } while (pix--); }<BR> }<BR> break;<BR> case 3 :<BR> {<BR> BYTE *sb = (BYTE *) (src+pix);<BR> int s1 = StainSrc(0);<BR> int s2 = StainSrc(1);<BR> int s3 = StainSrc(2);<BR> CApsLUT *lut1 = &(StainLUTS[0]);<BR> CApsLUT *lut2 = &(StainLUTS[1]);<BR> CApsLUT *lut3 = &(StainLUTS[2]);<BR> if(BrightField()) (<BR> do {<BR> dst[pix] = overlayColors(lutl->Lookup (sb[s1]), lut2->Lookup(sb[s2]), lut3->Lookup(<BR> sb[s3]));<BR> sb -= sizeof(APSCLR);<BR> } while(pix--);<BR> } else {<BR> do {<BR> dst[pix] = AddColors(lut1->Lookup (sb(s1]), lut2->Lookup(sb[s2]), lut3->Lookup(sb[s<BR> 3]));<BR> sb -= sizeof(APSCLR);<BR> } while(pix--);<BR> }<BR> }<BR> break;<BR> case 4:<BR> {<BR> BYTE *sb = (BYTE *) (src|pix);<BR> int s1 = StainSrc(0);<BR> int s2 = StainSrc(1);<BR> int s3 = StainSrc(2);<BR> int s4 = StainSrc(3);<BR> CApsLUT *lut1 = &(StainLUTS[0]);<BR> CApsLUT *lut2 = &(StainLUTS[1]);<BR> CApsLUT *lut3 = &(StainLUTS[2]);<BR> CApsLUT *lut4 = &(StainLUTS[3]);<BR> if(BrightField()) {<BR> do {<BR> dst(pix) = OverlayColors(lut1->Lookup(sb[s1]), lut2->Lookup(ab[s2]),<BR> lut3->Lookup(sb[s3]), lut4->Lookup (sb[s4]));<BR> sb -= sizeof(APSCLR); } while(pix--);<BR> } else {<BR> do {<BR> dst[pix] = AccColors(lut1->Lookup(sb[s1]), lut2->Lookup (sb[s2]),<BR> lut3->Lookup(sb[s3]), lut4->Lookup(sb[s4]));<BR> sb -= sizeof(APSCLR);<BR> } while(pix--);<BR> }<BR> }<BR> break;<BR> }<BR> }<BR> CApsStainSet::CApsStainSet() {<BR> memset(this, 0, sizeof(*this));<BR> }<BR> CApsStainSet::CApsStainSet(const char *name, int numStains, BOOL brightField,<BR> CApsStain *stain1, CApsStain *stain2,<BR> CApsStain *stain3, CApsStain *stain4)<BR> {<BR> memset(this,0,sizeof(*this));<BR> Name(name);<BR> NumStains(numStains);<BR> //this is the default<BR> //<BR> //this should be re-set<BR> //after a dataset kas been loaded.<BR> <P>//the setting should correlate<BR> //to the cprocesses (optical & chemical)<BR> //used to generate the data<BR> //as well as the color flags<BR> //that are set in the file,<BR> //<BR> StainSrc(0,2);<BR> StainSrc(1,1);<BR> StainSrc(2,0);<BR> StainSrc(3,3);<BR> BrightField(brightField);<BR> Stain(0,stain1);<BR> Stain(1,stain2);<BR> Stain(2,stain3);<BR> Stain(3,stain4); } CApsStainSet : : ~CXpsStainsec () { BOOL LoadAllsCainUserDefaults (void) CApsStainSet ttss-StainSets- let nss = NumStainSeta ; BOOL rv = FALSE ; if(! IniSetSection ("Stain, F^JjSZ)} recurn rv ; do if ( « erDefaultColors ()) TRUE ; SS+'f- ; ) while (--nss) : return rv ; } End of file: apsetain. cpp ***/ static char apslut_id[] = "SId:apslut.cpp,v 1.6 1999/05/10 18:39:15 benn Exp $";<BR> &num include <windows.h><BR> &num include <windowsx.h><BR> &num include <io.h><BR> &num include <fcntl.h><BR> &num include <stdio.h><BR> &num include <string.h><BR> &num include "cellvue.h"<BR> &num include "apsdll.h"<BR> &num include "tabarray.h"<BR> &num include "ini.h"<BR> &num include "apslut.h"<BR> &num include "color.h"<BR> &num include "fadebar.h"<BR> &num include "apsstain.h"<BR> /* global instance handle for this module */<BR> HINSTANCE hModule = 0;<BR> /* instance data pointer (only one allowed for this module) */<BR> LPAPSLUTINST psInst = 0;<BR> CApsStainSet *CurrentStainSet = NULL;<BR> int CurrentStainIdx = 0;<BR> BOOL ConstUpdate = FALSE;<BR> BOOL DontDoCB = FALSE;<BR> LPAPSSLICE lastSlice = NULL;<BR> LPAPSSLICE cleanSlice = NULL;<BR> typedef long (_cdecl *MsgHundler) (HWND,UINT,WPARAM,LPARAM);<BR> BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID);<BR> LRESULT CALLBACK MessageProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParcm); /*****************************************************************************/<BR> /* list of available plugins in this module */<BR> extern "C" _declspec(dllexport) APSPLUGINFO PluginList[] =<BR> {<BR> {<BR> "aps_2D_lut_plugin",<BR> "1.0",<BR> "Default 2D LUT Plugin",<BR> "2D",<BR> (MsgHandler) &MessageProc<BR> },<BR> NULL<BR> };<BR> /*****************************************************************************/<BR> /* save module handle when the OS loads the plugin */<BR> BOOL WINAPI DllMain (HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpReserved)<BR> {<BR> /* save global instance handle */<BR> hModule = hInstDLL;<BR> return TRUE;<BR> }<BR> inlinc void LUTConvert(void) {<BR> int p; //if(lastSlice->dwFlags&PLUGFLAGS_LUT_CONVERTED)<BR> // return;<BR> p=lastSlice->dwWidth*lastSlice->dwHeight<BR> CurrentStainSet->StainBuffer((APSCLR *)cleanSlice->psDta,<BR> (APSCLR *)lastSlice->psData,p,lastSlice->dwChannele);<BR> if(CurrentStainSet == &ApsDFRaw) {<BR> lastSlice->dwFlags = cleanSlice->dwFlags<BR> lastSlice->dwRGBFlags = cleanSlice->dwRGBFlags<BR> lastSlice->dwChannels = cleanSlice->dwChannels<BR> } else {<BR> //mark the slice as LUT converted<BR> lastSlice->dwFlags#=PLUGFLAGS_LUT_CONVERTED;<BR> //set the slice flags to reflect that it is now 3 color rgb data<BR> lastSlice->dwRGBFlags = RGBFLAGS_RED # RGBFLAGS_GREEN # RGBFLAGS_BLUE;<BR> lastSlice->dwChannels = 3;<BR> }<BR> }<BR> //recopy the clean data to the slice we sill send down the chain<BR> //we have to always send the slice we got, not a duplicate!<BR> //inline void CleanSlice(void) {<BR> // if(lastSlide->dwFlags&PLUGFLAGS_LUT_CONVERTED) {<BR> // memcpy(lastSlice->psData,cleanSlice->psData,<BR> // (lastSlice->dwWidth*lastSlice->dwHeight)*sizeof(APSCOLOR));<BR> // lastSlice->dwFlags = cleanSlice->dwFlage,<BR> // lastSlice->dwRGBFlags = cleanSlice->dwRGBFlags<BR> // lastSlice->dwChannels = cleanSlice->dwChannels<BR> // }<BR> //}<BR> void RefreshSlice(void) {<BR> if(!lastSlice)<BR> return; LUTConvert();<BR> ProduceOrthoSlice(lastSlice, psInst->hwnd);<BR> }<BR> void EnableDefaultsButtons(BOOL enable=TRUE) {<BR> HWND hwnd = psInst->hDlgWnd<BR> EnableWindow(GetDlgItem(hwnd,IDC_RESTOREBTN), enable);<BR> EnableWindow(GetDlgItem(hwnd,IDC_ORIGDEFAULTSBTN), enable);<BR> EnableWindow(GetDlgItem(hwnd,IDC_SAVEASDEFAULTSBTN), enable);<BR> }<BR> void LoadStainSetCombo(int);<BR> void SetCurrentStainSet(CApsStainSet *);<BR> /*****************************************************************************/<BR> /* main messnage handler for the plugin */<BR> LRESULT CALLBACK MessageProc(HWND hWnd, UINT uMeg, WPARAM wParam, LPARAM 1Param)<BR> {<BR> static BOOL newData = FALSE;<BR> static BOOL firstDS = TRUE;<BR> switch {uMsg}<BR> {<BR> case WM_APS_INIT;<BR> return FALSE;<BR> case WM_DESTROY:<BR> UnRegisterFadeBar(hModule);<BR> if(cleanSlice)<BR> DestroyOrthoSlice(cleanSlice);<BR> return FALSE;<BR> case WM_APS_CONSTRUCTOR:<BR> /* initialize an instance of parameter data */<BR> RegisterfAdeBar(hModule);<BR> psInst = (LPAPSLUTINST) apsmalloc0(sizeof(APSLUTINST));<BR> psInst->hwnd = hWnd;<BR> CreateTabDialog("SECTION (2D)", "Stain", hModule, (LPVOID)psInst, MAKEINTRESOURCE (IDD_D<BR> IALOG1), (DLGPROC) Dialoglproc);<BR> return (LONG)hWnd; case WM_APS_NEW_DATASET_LOADED:<BR> newData = TRUE;<BR> return FALSE;<BR> case WM_APS_SLICE_PACKET:<BR> {<BR> LPAPSSLICE slice=(LPAPSSLICE) wParam;<BR> if(cleanSlice) {<BR> DestroyOrthoSlice(cleanSlice);<BR> cleanSlice = NULL;<BR> }<BR> lastSlice = slice;<BR> cleanSlice = DuplicateOrthoSlice=(slice);<BR> //new data to adjust to<BR> if(newData) {<BR> newData = FALSE;<BR> if (firstDS) {<BR> EnableWindow (GetDlgItem(psInst->hDlgWnd, IDC_STAINSET_COMBO),TRUE);<BR> }<BR> LoadStainSetCombo((int)slice->dwChannels);<BR> //if this is the first dataset ever or<BR> //we are not in raw (we don't change out of raw normally, one size fits all)<BR> //but we START in raw mode 3047 assume a stain is wanted. Whew.<BR> if(firstDs#CurrentStainSet!=&ApsDFRaw) {<BR> if(firstDS) {<BR> firstDS = FALSE;<BR> }<BR> if(CurrentStainSet->NumStains()!=(int)alice->dwChannels) {<BR> int ss=0; for(ss;ss<NumStrainSets;ss++) {<BR> if(StainSets[ss]->NumStains()==(int)slice->dwChannels) {<BR> break;<BR> }<BR> }<BR> //<BR> //set to raw if no other stain set works<BR> //<BR> if(ss==NumStainsSets) {<BR> SetCurrentStainSet(&ApsDFRaw);<BR> } else {<BR> SetCurrentStainSet(StainSets[ss]);<BR> }<BR> }<BR> }<BR> }<BR> RefreshSlice();<BR> return FALSE;<BR> }<BR> break;<BR> }<BR> /* call default windows proc */<BR> return DefWindowProo (hWnd, uMsg, wParam, 1Param);<BR> }<BR> void UpdateFadeBars(void) {<BR> HWND hWnd = psInst->hDlgWnd<BR> CApsStain *stain = CurrentStainSet->Stain(CurrentStainIdx);<BR> HSVCOLOR *activeColor = stain ? stain->CurrentcolorPtr() : NULL,<BR> HSVCOLOR thsV = {0.0,0.0,0.0};<BR> HSVCOLOR thsV2 = {0.0,0.0,0.0};<BR> HWND hFB;<BR> if(activeColor) {<BR> thsv = *activeColor;<BR> thsv2 = thsv; }<BR> hFB = GetDlgItem(hWnd, IDC_FADEBAR);<BR> if(CurrentStainSet->BrightField()) {<BR> thsv2.s = 0.0;<BR> thsv2.v = 1.0;<BR> } else {<BR> thsv2.s = 1.0;<BR> thsv2.s = 0.0;<BR> }<BR> SendMessage(hFB,WM_FBSETLCOLOR,0,(LPARAM)&thsv2);<BR> thsv2 = thsv;<BR> SendMessage(hFB,WM_FBSETLCOLOR,0,(LPARAM)&thsv2);<BR> RedrawWindow(hFB,NULL,NULL,RDW_INVALIDATE#RDW_UFDATENOW);<BR> hFB = GetDlgItem(hWnd,IDC_HUEFADE) ;<BR> thsv.h = stain ? (double)stain->HueMin() : 0.0;<BR> SendMessage(hFB,WM_FBSETLCOLOR,0,(LPARAM)&thsv);<BR> thsv.h = stain ? (double)stain->HueMin() : 0.0;<BR> SendMessage(hFB,WM_FBSETLCOLOR,0,(LPARAM)&thsv);<BR> thsv.h=thsv2.h;<BR> RedrawWindow(hFB,NULL,NULL,RDW_INVALIDATE#RDW_UPDATENOW);<BR> hFB = GetDlgItem(hWnd,IDC_SATFADE) ;<BR> thsv.s=0.0;<BR> SendMessage(hFB,WM_FBSETLCOLOR,0,(LPARAM)&thsv);<BR> thsv.s=1.0;<BR> SendMessage(hFB,WM_FBSETLCOLOR,0,(LPARAM)&thsv);<BR> thsv.s=thsv2.s;<BR> RedrawWindow(hFB,NULL,NULL,RDW_INVALIDATE#RDW_UPDATENOW);<BR> hFB = GetDlgItem(hWnd.IDC_VALFADE);<BR> thsv.v=0.0;<BR> SendMessage(hFB,WM_FBSETLCOLOR,0,(LPARAM)&thsv);<BR> thsv.v=1.0;<BR> SendMessage(hFB,WM_FBSETLCOLOR,0,(LPARAM)&thsv);<BR> RedrawWindow(hFB,NULL,NULL,RDW_INVALIDATE#RDW_UPDATENOW);<BR> } void HandleSliderMessage(HWND hWnd, int nScrollCode, int nPos, HWND HwndScrollBar) {<BR> char numStr[32];<BR> int dPos=0;<BR> HWND HwndEdit = NULL;<BR> int min=0,max=100;<BR> double *valP,divisor=100.0;<BR> char *fmt = "%d%%";<BR> int maxDisp = 101;<BR> BOOL arrowKey = FALSE;<BR> HSVCOLOR * activeColor = CurrentStainSet->Stain[CurrentStainIdx)->currentColorPtr();<BR> if(DontDoCB)<BR> return;<BR> if(hwndScrollBar == GetDlgItem(hWnd,IDC_HUESLIDER)) {<BR> hwndEdit = GetDlgItem(hWnd, IDC_HUETEXT) ;<BR> valp=&(activeColor->h);<BR> divisor=1.0;<BR> fmt="%d";<BR> maxDisp = 360;<BR> } else if(hwndScrollBar == GetDlgItem(hWnd, IDC_SATSLIDER)) {<BR> hwndEdit = GetDlgItem(hWnd, IDC_SATTEXT);<BR> valp=&(activeColor->s);<BR> } else if(hwndScrollBar == GetDlgItem(hWnd, IDC_VALSLIDER)) {<BR> hwndEdit = GetDlgItem(hWnd, IDC_VALTEXT);<BR> valp=&(activeColor->v);<BR> }<BR> GetScrollRange(hwndScrollBar,SB_CTL,&min,&max);<BR> switch(nScrollCode) {<BR> case SB_PAGELEFT:<BR> dPos-=20;<BR> case SB_PAGERIGHT: dPos+=ll ; caseSBLINELEFT : do-=2 ; caseSBMNERIGHT ; dPos nPos = Get5crollpos (hwndScrollBar, SB CTL) + dPos ; arrowKey = TRUE ; caseSB TtiUMBTRACK : if(nPosomin) { nPos_min ; else if (oPosomax) ( n. Pos=max : } SecScrollPos(hwndScrollBar, SB CTL, nPos, TRUB) ; sprintf {oumstr, £mt, nPoszmtxDisp) SetWindowText (handEdit, numstr) ; *valP = (double) nPos/divisor ; UpdataFadeBars {) ; iff SConstUpdate&L ! arrowKey) break ; cas SBSCROL : t CurrentStainSet->BuildLUTS (CurrentStainldx) : RereshSliceO : } break ; }. t voidReloadRSVTextst) t HWND hWnd = pslest->hDlstadi CApsStain'stain = currentStaiiSet->stain (CurrentStainIdx) HSVCOLOR *activeColor = stain ? srain->CurrentColorPtr () : NULL ; int hmin stain ? stain->HueMin () : o int hoax _ stain ? stain->HueMax (). O charnumstr [321 ; inth = 0, s = 0, v = 0 ; if(activeColor) {<BR> h = (int) activeColor->h<BR> s = (int) (activeColor->s*100.0);<BR> v = (int) (activeColor->v*100.0);<BR> }<BR> sprintf(numStr,"%d",h%361);<BR> SetWindowText(GetDlgItem(hWnd,IDC_HUETEXT),numStr);<BR> sprintf(numStr,"%d%%",s);<BR> SetWindowText(GetDlgItem(hWnd,IDC_SATTEXT),numStr);<BR> sprintf(numStr,"%d%%",v);<BR> SetWindowText(GetDlgItem(hWnd,IDC_VALTEXT),numStr);<BR> if(h<hmin) {<BR> h+=360;<BR> } else if (h>hmax) {<BR> h-=360;<BR> }<BR> if(IsWindowEnabled(GetDlgItem(hWnd,IDC_HUESLIDER))) {<BR> SetScrollPos(GetDlgItem(hWnd,IDC_HUESLIDER),SB_CTL,h,TRUE);<BR> SetScrollPos(GetDlgItem(hWnd,IDC_SATSLIDER),SB_CTL,s,TRUE);<BR> SetScrollPos(GetDlgItem(hWnd,IDC_VALSLIDER),SB_CTL,v,TRUE);<BR> }<BR> }<BR> static int StainRadioIds[MAXSTAINS+] = {IDC_S1COLORRADIO, IDC_S2COLORRADIO, IDC_S3COLORRADIO, IDC_S4<BR> COLORRADIO, 0};<BR> void SetCurrentStain(int stainIdx) {<BR> int hmin=0, hmax=0;<BR> CApsStainSet *ss = CurrentStainSet;<BR> CApeStain *stain;<BR> HWND hueSlider = GetDlgItem(psInst->hDlgWnd, IDC_HUESLIDER) ; CurrentStainIdx = stainIdx;<BR> stain = ss->Stain(StainIdx);<BR> if(stain) {<BR> hmin = stain->HueMin();<BR> hmax = stain->HueMax();<BR> }<BR> SetScrollRange(hueSlider,SB_CTL,hmin,hmax,TRUE);<BR> ReloadHSVTexts();<BR> UpdateFadeBars();<BR> if(ss->NumStains()>1) {<BR> int ns = ss->NumStains();<BR> for(int s=0;s<nss++) {<BR> CheckDlgButton(psInst->dDlgWnd,StainRadioIds[s],==CurrentStainIdx);<BR> }<BR> }<BR> }<BR> static void EnableHSVSliders (BOOL flag) {<BR> EnableWindow(GetDlgItem(psInst->hDlgWnd, IDC_HUESLIDER),flag);<BR> EnableWindow(GetDlgItem(psInst->hDlgWnd, IDC_SATSLIDER),flag);<BR> EnableWindow(GetDlgItem(psInst->hDlgWnd, IDC_VALSLIDER),flag);<BR> }<BR> void LoadStainSetCombo(int chans) {<BR> int esi;<BR> int nss = NumStainSets;<BR> HWND comboBox = GetDlgItem(psInst->hDlgWnd,IDC_STAINSET_COMBO);<BR> CApsStainSet *ss;<BR> int comboIdx=0;<BR> SendMessage(comboBox,CB_RESETCONTENT,0,0);<BR> for(ssi = 0; ssi < nss; ssi++) {<BR> ss = StainSets[ssi];<BR> //if[ss->numStains()==0#ss->NumStains()<=chans) {<BR> comboIdx=SendMessage(combobox,CB_ADDSTRING, 0, (LPARAM) ss->Name());<BR> SendMessage(comboBox,CB_SETITEMDATA, comboIdx, (LPARAM) ss);<BR> //}<BR> }<BR> } void SetCurrentStainSet(CApsStainSet *ss) {<BR> HWND radio;<BR> int s;<BR> SendMessage(GetDlgItem(psInst->hDlgWnd,IDC_STAINEST_COMBO),CB_SELECTSTRING, -1, (LPARAM) ss->Name()<BR> );<BR> CurrentStainSet = ss;<BR> if(as->NumStains()) {<BR> EnableHSVSliders(TRUE);<BR> if(ss->NumStains()>1) {<BR> int ns = ss->NumStains();<BR> for(s=0;s<nss++) {<BR> radio = GetDlgItem(psInst->hDlgWnd,StainRadioIds[s]);<BR> SetWindorTExt(radio,ss->Stain(s)->Name());<BR> ShowWindow(radio.SW_SHOW);<BR> }<BR> while(StainRadioIds[s]) {<BR> ShowWindow(GetDlgItem(psInst->hDlgWnd.StainRadioIds[s]), SW_HIDE);<BR> s++;<BR> }<BR> } else {<BR> for(s=0;StainRadioIds[s];s++)<BR> ShowWindow(GetDlgItem(psInst->hDlgWnd,StainRadioIds[s]),SW_HIDE);<BR> }<BR> SetCurrentStain(0);<BR> ss->BuildLUTS();<BR> EnableDefaultsButtons(TRUE);<BR> } else { EnableHSVSliders(FALSE);<BR> EnableDefaultsButtons(FALSE);<BR> for(s=0;StainRadioIds[s];s++)<BR> ShowWindow(GetDlgItem(psInst->hDlgWnd.StainRadioIds[s]),SW_HIDE);<BR> ReloadHSVTexts();<BR> UpdateFadeBars();<BR> }<BR> SendMessageToAllPluginInstances(WM_APS_BRIGHTFIELD_MODE,0,ss->BrightField());<BR> }<BR> /*****************************************************************************/<BR> /* dialog box proc */<BR> BOOL Dialog1Proc( HWND hWnd, UINT dwMsg, WPARAM wParam, LPARAM 1Param )<BR> {<BR> static BOOL gotFocus = FALSE;<BR> switch ( dwMsg )<BR> {<BR> case MW_INITIALOG:<BR> psInst->hDlgWnd = hWnd;<BR> LoadAllStainUserDefaults();<BR> EnableHSVSliders(FALSE);<BR> EnableDefaultsButtons(FALSE);<BR> SendMessage(GetDlgItem(hWnd,IDC_FADEBAR),WM_FBSETMODE,0,FBM_HSV);<BR> SendMessage(GetDlgItem(hWnd,IDC_HUEFADE),WM_FBSETMODE,0,FBM_HSV);<BR> SendMessage(GetDlgItem(hWnd,IDC_SATFADE),WM_FBSETMODE,0,FBM_HSV);<BR> SendMessage(GetdlgItem(hWnd,IDC_VALFADE),WM_FBSETMODE,0,FBM_HSV);<BR> SetScrollRange(GetDlgItem(hWnd,IDC_SATSLIDER),SB_CTL,0.100,TRUE);<BR> SetScrollRange(GetDlgItem(hWnd,IDC_VALSLIDER),SB_CTL,0,100,TRUE);<BR> EnableWindow(GetDlgItem(hWnd,IDC_STAINEST_COMBO),FALSE);<BR> SetCurrentstainSet(&ApsDFRaw);<BR> break; case WM_RBUTTONDOWN:<BR> if((wParam&MK_CONTROL) && (wParam@MK_SHIFT)) {<BR> ConstUpdate=!ConstUpdate;<BR> if(CostUpdate) {<BR> Beep(880,250);<BR> } else {<BR> Beep(440,250);<BR> }<BR> }<BR> break;<BR> case WM_COMMAND:<BR> switch ( LOWORD(wParam) )<BR> {<BR> case IDC_S1COLORRADIO:<BR> SetCurrentStain(0);<BR> break;<BR> case IDC_S2COLORRADIO:<BR> SetCurrentStain(1);<BR> break;<BR> case IDC_S3COLORRADIO:<BR> SetCurrentStain(2);<BR> break:<BR> case IDC_S4COLORRADIO:<BR> SetCurrentStain(3);<BR> break;<BR> case IDC_STAINSET_COMBO:<BR> switch(HIWORD(wParam)) {<BR> case CBN_SELECHANGE:<BR> {<BR> int surSel = SendMessage((HWND)lParam.CB_GETCURSEL.0.0);<BR> CApsStainSet *ss = (CApsStainSet *)SendMessage((HWND))lParam.CB_GETITEMDA<BR> TA, (WPARM)curSel,0); if(ss!=CurrentStainSet) {<BR> SetCurrentStainSet(ss);<BR> RefreshSlice();<BR> }<BR> }<BR> break;<BR> }<BR> break;<BR> case IDC_SAVEASDEFAULTSBTN:<BR> if(!clcanSlice)<BR> break;<BR> CurrentStainSet->SaveUserDafaultColors();<BR> break;<BR> case IDC_ORIGDEFAULTSBTN:<BR> if(!cleanslice)<BR> break;<BR> CurrentStainSet->RestoreDefaultColors();<BR> ReloadHSVTexts();<BR> UpdateFadeBars();<BR> CurrentStainSet->BuildLUTS();<BR> RefreshSlice();<BR> break;<BR> case IDC_RESTOREBTN:<BR> if(!cleanSlice)<BR> break;<BR> CurrentStainSet->RestoreUserDefaultColors();<BR> ReloadHSVTexts();<BR> UpdateFadeBars();<BR> CurrentStainSet->BuildLUTS();<BR> RefreshSlice();<BR> RefreshSlice(); break: case XDCANCEL : EndDialog (hWnd, FALSE) break ; ) break ; caseWM IISCROLL : HandleSliderMessage (hwnd, LOWORD (wParam), HIWORD (wparam). (WND) lParaml ; break; /*don't close the dialog box "/ return FALSE : End of file ; apslut. c * asplut.h<BR> &num ifndef _APSLUT_H-<BR> &num define -APSLUT_H_<BR> &num ifdef _cplusplus // pre<BR> vent name mangling<BR> extern "C" {<BR> &num endif ********/ ********/ //include resource dialog headers that were generated //by Visual C++ #include'.. \rs\dialog
1. l. h" defines //defines //destines structures //structures //streetures //2D instance data typedefstruct APSLUTINST t HWND hDlgWnd ; apslut. h // //c all your instance data // } APSLUTINST, *LPAPSLUTINST ; externs //externs //externS //module handle externHINSTRANCE t@ {oduSe externc*****x*******rx******r*. x. x**r********. . ******* ********/ prototypes //apslut.c LRESULT CALLBACK MessageProc HW hWrid, UINT uMsg, WPARAD2 wPar am, bPAF1ud lPar2m) ; BOOL DialoglProct H0nMD hEEnd, UNET dwKsg, WP am. LPARAM lParam); BOOL ARAM wParam, IPAM lParam) ; UINT API'ENTRY OFNHookProc (HMND hdlg, UINT uiMsg, WP wPa ram,LPARAM IParam) ; #ifdefcplusplus vent name mangling I endiS//cplusplus #endif//APSLUTH /*** End of file : apslut. h ***/ apsstain.h<BR> &num ifndef _APSSTAIN_H_<BR> &num define _APSSTAIN_H_<BR> &num include "ApsFileTypes.h"<BR> const int MAXSTAINS = 4;<BR> class CApsLUT {<BR> private:<BR> APSCLR m_Entries[256];<BR> inline APSCLR *Entries(void) {<BR> return m_Entries;<BR> }<BR> public:<BR> void Build(HSVCOLOR firstColor,HSVCOLOR lastColor,int firstIdx<BR> =0, int lastIdx=255);<BR> inline APSCLR Lookup(BYTE idx) {<BR> return Entries() [idx];<BR> }<BR> inline APSCLR BaseColor(void) {<BR> return Lookup(255);<BR> }<BR> CApsLUT();<BR> CApsLUT();<BR> };<BR> class CApsStain {<BR> private: apsstain.h<BR> const char *m_Name;<BR> //<BR> //initial color<BR> //<BR> HSVCOLOR m_DefaultColor;<BR> HSVCOLOR m_UserDefaultColor;<BR> int m_HueMin;<BR> int m_HueMax;<BR> //<BR> //neither of these are<BR> //adjusted from the UI!<BR> //<BR> int m_XOverVal;<BR> HSVCOLOR m_XOverColor;<BR> //is crossover color<BR> //solid from xover point to end<BR> //or does it fade from<BR> //last value of base color toward<BR> //the xover color<BR> BOOL m_XOverFade;<BR> //<BR> //current color (tweaked via sliders)<BR> //<BR> HSVCOLOR m_CurrentColor; apsstain. h public : inline const char *Name (void) const { return m Name ; I inline const char *Name (const char *name) ( retUrn t Name = name; I inline HSVCOLOR DefaultColor (sold) conat { return m_DefaultColor ; inline HSVCOLOR DefaultColor (FISVCOLOR clr) m_DefaultColor = clr ; return m_DefaultColor, } inline HSVCOLOR UserDefaultColor (void) const { return m'UserDefaultColor ; apsstain.h<BR> inline HSVCOLOR UserDefaultColor(HSVCOLOR clr) {<BR> m_UserDefaultColor = clr;<BR> return m_UserDefaultColor;<BR> }<BR> inline int HueMin(void) const {<BR> return m_HueMin;<BR> }<BR> inline int HueMin(int hm) {<BR> return m_HueMin = hm;<BR> }<BR> inline int HueMax(void) const {<BR> return m_HueMax;<BR> }<BR> inline int HueMax(int hm) {<BR> return m_HueMax = hm;<BR> }<BR> inline HSVCOLOR CurrentColor(void) const {<BR> return m_CurrentColor;<BR> }<BR> inline HSVCOLOR *CurrentColorPtr(void) {<BR> return &m_CurrentColor;<BR> } apstain.h<BR> inline HSVCOLOR CurrentColor(HSVCOLOR clr) {<BR> return m_CurrentColor = clr;<BR> }<BR> inline HSVCOLOR OverColor(void) const {<BR> return m_XOverColor;<BR> }<BR> inline HSVCOLOR XOverColor(HSVCOLOR clr) {<BR> return m_XOverColor = clr;<BR> }<BR> inline int XOverVal(void) const {<BR> return m_XOverVal;<BR> }<BR> inline int XOverVal(int v) {<BR> return m_XOverVal = v;<BR> }<BR> inline BOOL XOverFade(void) const { apsstain. h retuXdverFade ; inline BOOL XOverFade (BOOL f) { return mXOverFade = f; capsstaino ; CApsStain (const char *name, HSVCOLOR defColor, int hueMin, int h hou CApsSta. in (const char *name, HSVCOLOR defColoc. int hueMin, int h' eMax,HSVCOLOR xOverColor, inh, BOOL tt x0'crerVal, BppT, xOverFade) ; sCApsStain () } ; classCApsStainSet { private: const char *MName ; int m_NumStains ; BOOL mBrightField ; CApsStain*mStains [MMSTAINS] ; intm StainSrcs [MAXSTArNS] ; public : inline const. char *Name (void) cons t return m_Name ; 3 apstain.h<BR> inline const char *Name(const char *name) {<BR> return m_Name = name;<BR> }<BR> inline int NumStains(void) const {<BR> return m_NumStains;<BR> }<BR> inline int NumStains(int ns) {<BR> return m_NumStains = ns;<BR> }<BR> inline int StainSrc (int stainIdx) {<BR> if((unsigned)stainIdx<(unsigned)NumStains())<BR> return m_StainSrcs [stainIdx] ;<BR> return 1;<BR> }<BR> inline int StainSrc (int stainIdx, int channelIdx) {<BR> if((unsigned)stainIdx<(unsigned)NumStains())<BR> return m_StainSrcs[stainIdx] = channelIdx; color.h<BR> &num ifndef _COLOR_H_<BR> &num define _COLOR_H_<BR> typedef struct {<BR> double h;<BR> double s;<BR> double v;<BR> } HSVCOLOR;<BR> typedef struct {<BR> double r;<BR> double g;<BR> double b;<BR> } DRGBCOLOR;<BR> _inline int MIN(int a, int b) {<BR> return a<b?a:b;<BR> }<BR> _inline int MAX(int a, int b) {<BR> return a>b?a:b;<BR> }<BR> _inline double DMIN (double a, double b) {<BR> return a>b?a:b;<BR> }<BR> _inline double DMAX (double a, double b) {<BR> return a>b?a:b;<BR> }<BR> _inline int ABS (int a) { color.h<BR> return a<0?a:a;<BR> }<BR> _inline void DRGB2HSV (DRGBCOLOR *drgb, HSVCOLOR *hsv) {<BR> double max=DMAX(DMAX(drgb>r,drgb>g),drgb>b) ;<BR> double min=DMIN(DMIN(drgb>r,drgb>g),drgb>b) ;<BR> if((hsv>v=max)!=0.0) {<BR> hsv>s=(maxmin)/max;<BR> } else {<BR> hsv>s=0.0;<BR> hsv>h=0.0;<BR> return;<BR> }<BR> if(!hsv>s) {<BR> hsv>h=0.0;<BR> return;<BR> }<BR> if(drgb>r==max) {<BR> hsv>h = (drgb>gdrgb>b)/(maxmin);<BR> } else if(drgb>g==max) {<BR> hsv>h = 2.0 + (drgb>bdrgb>r)/(maxmin);<BR> } else if(drgb>b==max) {<BR> hsv>h = 4.0 + (drgb>rdrgb>g)/(maxmin);<BR> } color.h<BR> hsv>h*=60;<BR> if(hsv>h<0.0) {<BR> hsv>h+=360.0;<BR> } else if(hsv>h>=360.0) {<BR> hsv>h=360.0;<BR> }<BR> }<BR> _inline COLORREF DRGB2COLORREF (DRGBCOLOR *drgb) {<BR> return RGB(<BR> (int) ((drgb>r*255.0)+0.5),<BR> (int) ((drgb>g*255.0)+0.5),<BR> (int) ((drgb>b*255.0)+0.5));<BR> }<BR> _inline void COLORREF2DRGB(COLORREF cr, DRGBCOLOR *drgb) {<BR> drgb>r=(double)GetRValue(cr)/255.0;<BR> drgb>g=(double)GetGValue(cr)/255.0;<BR> drgb>b=(double)GetBValue(cr)/255.0;<BR> }<BR> _inline void HSV2DRGB (HSVCOLOR *hsv,DRGBCOLOR *drgb) { color. h if (hsv>s=0. 0) { drgb>r=drgb>g=drgbb=hsvv ; else { int i, double f, p, q, t, h ; h = ((hsv>h >= 360. 0)? 360. 0 : hsv>h) ; h/= 60 : 0 ; i= (int) h; f=h(double) i : p=hsv>v* (1. Ohsv>s) ; q=hsv>v* (1.0 (hsv>s*f)) ; t=hsv>v*(l (hsv>s* (lf))) ; switch (i) { case 0 : drgb>r=hsv>v ; drgb>gtidrgb>b p ; break; case 1 : drgb>r=q ; drgb>ghsv>vdrb>b_p ; break ; p;bxeak; case 2 : drgb>r=p ; drgb>g= : hsv>v ; drgbb=t ; break; case 3 : drgb>r=p ; drgb>g=A ; drgb>b=hsv>v ; break ; case 4 : drgb>r=t ; drgb>g=p ; drgb>b=hsv>v ; break ; case 5 : drgb>r=hsv>v ; drg »>gp ; drgbob=q ; break ; color.h<BR> _inline COLORREF HSV2COLORREF (HSVCOLOR *c) {<BR> DRGBCOLOR drgp;<BR> HSV2DRGB(c,&drgb);<BR> return DRGB2COLORREF(&drgb);<BR> }<BR> _inline void COLORREF2HSV(COLORREF cr,HSVCOLOR *hsv) {<BR> DRGBCOLOR drgb;<BR> COLORREF2DRGB(cr,&drgb);<BR> DRGB2HSV(&drgb,hsv);<BR> }<BR> &num ifdef _CELLVUE_H_<BR> _inline void COLORREF2APS(COLORREF cr,APSCOLOR *aps) {<BR> *aps=*((APSCOLOR *)&cr);<BR> }<BR> _inline COLORREF APS2COLORREF(APSCOLOR *aps) {<BR> return *((COLORREF *)aps);<BR> }<BR> _inline APS2DRGB(APSCOLOR *aps,DRGBCOLOR *drgb) {<BR> drgb>r=(double)(aps>r)/255.0; color.h<BR> drgb>g=(double)(aps>g)/255.0;<BR> drgb>b=(double)(aps>b)/255.0;<BR> }<BR> _inline DRGB2APS(DRGBCOLOR *drgb, APSCOLOR *aps) {<BR> aps>r = (int) ((drgb>r*255.0)+0.5);<BR> aps>g = (int) ((drgb>g*255.0)+0.5);<BR> aps>b = (int) ((drgb>b*255.0)+0.5);<BR> }<BR> _inline void HSV2APS(HSVCOLOR *hsv,APSCOLOR *aps) {<BR> DRGBCOLOR drgb;<BR> HSV2DRGB(hsv,&drgb);<BR> DRGB2APS(&drgb,aps);<BR> }<BR> _inline void APS2HSV(APSCOLOR *aps, HSVCOLOR *hsv) {<BR> DRGBCOLOR drgb;<BR> APS2DRGB(aps,&drgb);<BR> DRGB2HSV(&drgb,hsv);<BR> }<BR> &num endif //_CELLVUE_H_<BR> &num endif //_COLOR_H_<BR> /*** End of file: color.h ***/ fadebar.c<BR> static char fadebar_id[] = "$Id: fadebar.c,v 1.2 1998/12/16 02:10:10 b<BR> enn Exp $";<BR> &num include <windows.h><BR> &num include <windowsx.h><BR> &num include "fadebar.h"<BR> &num include "color.h"<BR> _inline COLORREF FadeRGBColor(int w,int x,COLORREF c1,COLORREF c2) {<BR> double frac=(double)x/(double)w;<BR> double ifrac=1.0frac;<BR> int r,g,b;<BR> r=(int) (frac*(double)GetRValue(c2)+ifrac*(double)GetRValue(c1)<BR> +0.5);<BR> g=(int) (frac*(double)GetGValue(c2)+ifrac*(double)GetGValue(c1)<BR> +0.5);<BR> g=(int) (frac*(double)GetGValue(c2)+ifrac*(double)GetGValue(c1)<BR> +0.5);<BR> return RGB(r,g,b);<BR> }<BR> _inline COLORREF FadeHSVColor (int w, int x, HSVCOLOR *c1, HSVCOLOR *c2) {<BR> double frac=(double)x/(double)w;<BR> double ifrac=1.0frac;<BR> HSVCOLOR t;<BR> t.h=frac*c2>h+ifrac*c1>h<BR> t.s=frac*c2>s+ifrac*c1>s<BR> t.v=frac*c2>v+ifrac*c1>v<BR> return HSV2COLORREF (&t);<BR> } fadebar.c<BR> typedef struct {<BR> COLORREF leftRGBColor;<BR> COLORREF rightRGBColor;<BR> HSVCOLOR leftHSVColor;<BR> HSVCOLOR rightHSVColor;<BR> int mode, w, h;<BR> HDC hdc;<BR> } FadeBarState;<BR> LRESULT CALLBACK FadeBarProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPAR<BR> AM 1Param) {<BR> FadeBarState *fbs = (FadeBarState *)GetWindowLong (hWnd,GWL_USE<BR> RDATA) ;<BR> switch (uMsg) {<BR> case WM_SHOWWINDOW:<BR> if (fbs&&!fbs>w) {<BR> RECT winRect;<BR> //save our window dimensions for use later.<BR> <P>//we don't have to worry about resizing the<BR> tab dialogs are const size.<BR> <P>GetWindowRect (hWnd,&winRect);<BR> fbs>w=winRect.rightwinRect.left;<BR> fbs>h=winRect.bottomwinRect.top; fadebar.c<BR> //the window class style for the fade bar spec<BR> ifies<BR> //OWNDC that is a DC is allocated for each i<BR> nstance<BR> //you only have to get the dc once as soon as<BR> it is valid and<BR> //release it once when you are done with the w<BR> indow<BR> //saves all that Get/Release DC'ing during pai<BR> nting<BR> fbs>hdc=GetDC(hWnd);<BR> }<BR> return DefWindowProc (hWnd, uWsg, wParam, lParam);<BR> case WM_CREATE:<BR> fbs = (FadeBarState *)malloc (sizeof(*fbs));<BR> memset (fbs, 0, sizeof (*fbs));<BR> fbs>mode @BM_RGB;<BR> fbs>left @Color = RGB (255,255,255);<BR> fbs>right@GBColor = RBG (255,0,255);<BR> fbs>leftHSVColor.h = 0.0;<BR> fbs>leftHSVColor,s = 1.0; fadebar.c<BR> fbs>leftHSVColor.v = 1.0;<BR> fbs>rightHSVColor.h=359.0;<BR> fbs>rightHSVColor.s=1.0;<BR> fbs>rightHSVColor.v=1.0;<BR> SetWindowLong (hWnd, GWL_USERDATA, (long) fbs) ;<BR> return DefWindowProc (hWnd, uMsg, wParam, lParam) ;<BR> case WM_DESTROY:<BR> //we are done with the dc for good now.<BR> <P>ReleaseDC (hWnd, fbs>hdc) ;<BR> free(fbs) ;<BR> return DefWindowProc (hWnd, uMsg, wparam, lParam) ;<BR> case WM_PAINT:<BR> {<BR> int x;<BR> COLORREF curColor;<BR> //create a pen of the leftend color of the ba<BR> r<BR> //select it in and save the old pen (to restor<BR> e later)<BR> HPEN oldPen =<BR> (HPEN) SelectObject (fbs>hdc,<BR> CreatePen (PS_S<BR> OLID, 1, fadebar.c<BR> fbs>mode==FBM_RGB?fbs>leftRGBColor:HSV2COLORREF (& (fbs>leftHSVColor)<BR> ))) ;<BR> //draw the first vertical line of the bar<BR> MoveToEx (fbs>hdc, 0, 0, NULL) ;<BR> LineTo (fbs>hdc, 0, fbs>h) ;<BR> //loop through the rest of the lines<BR> for (x=1;x<fbs>wx++) {<BR> CurColor = fbs>mode==FBM_RGB ?<BR> FadeRGBColor (fbs>w,x,fbs>leftRGBColor, fbs>rightRGBColor) :<BR> FadeHSVColor (fbs>w,x,&(fbs>leftHSVColor), & (fbs>rightHSVColor)) ;<BR> //when we select the next pen we creat<BR> e, we<BR> //get back the handle of the last one<BR> we created/selected...delete it<BR> DeleteObject(<BR> //select a new pen for the nex<BR> t vertical line<BR> SelectObject (fbs>hdc,<BR> //create a pen of the<BR> appropriately blended color for the next fadebar.c<BR> vline<BR> //solid (not dashed) p<BR> en with a width of 1 pixel<BR> CreatePen (PS_SOLID, 1,<BR> //do a weighte<BR> d blend of the left & right colors based on<BR> our x pos<BR> curColor))) ;<BR> //move to the top of our current vlin<BR> e<BR> MoveToEx(fbs>hdc,x,0,NULL);<BR> //draw our current vline to the botto<BR> m<BR> LineTo(fbs>hdc,x,fbs>h);<BR> }<BR> //restore the old pen and delete the last<BR> //pen we created (as returned from selectobjec<BR> t())<BR> DeleteObject (SelectObject (fbs>hdc,oldPen));<BR> //let windows know that we actually did redraw<BR> ValidateRect (hWnd,NULL); fadebar.c<BR> }<BR> break;<BR> case WM_FBSETLCOLOR:<BR> if (fbs>moe == FBM_RGB)<BR> fbs>leftRGBColor = (COLORREF) lParam;<BR> else if (fbs>mode == FBM_HSV && lParam)<BR> memcpy(&(fbs>leftHSVColor), (void *)lParam,siz<BR> eof (HSVCOLOR));<BR> break;<BR> case WM_FBSETRCOLOR:<BR> if (fbs>mode = FBM_RGB)<BR> fbs>rightRGBColor = (COLORREF) lParam;<BR> else if (fbs>mode == FBM_HSV && lParam)<BR> memcpy(&(fbs>rightHSVColor), (void *)lParam, si<BR> zeof (HSVCOLOR));<BR> break;<BR> case WM_FBGETLCOLOR:<BR> if (!lParam)<BR> break;<BR> if (fbs>mode == FBM_RGB)<BR> *((COLORREF *)LParam) = fbs>leftRGBColor;<BR> else if (fbs>mode == FMB_HSV)<BR> memcpy((void *)lParam, & (fbs>leftHSVColor), siz<BR> eof (HSVCOLOR));<BR> break;<BR> case WM_FBGETRCOLOR:<BR> if (!lParam) fadebar.c<BR> break;<BR> if (fbs>mode == FBM_RGB)<BR> *((COLORREF *)lParam) = fbs>rightRGBColor;<BR> else if (fbs>mode == FBM_HSV)<BR> memcpy((void *)lParam,&(fbs>rightHSVColor),si<BR> zeof (HSVCoLOR));<BR> break;<BR> case WM_FBSETMODE:<BR> fbs>mode = lParam;<BR> if (fbs>mode!=FBM_HSV && fbs>mode!=FBM_RGB)<BR> fbs>mode = FBM_INACTIVE;<BR> break;<BR> default:<BR> return DefWindowProc (hWnd, uMsg, wParam, lParam) ;<BR> }<BR> return 0;<BR> }<BR> BOOL RegisterFadeBar(HINSTANCE hInstance) {<BR> WNDCLASSEX wc;<BR> //ream it clean<BR> memset (&wc,0,sizeof(wc));<BR> //set the few necessary members<BR> //always and everywhere...<BR> wc.cbSize = sizeof (wc); fadebar.c<BR> //the message handler<BR> wc.lpfnWndProc = FadeBarProc;<BR> //window class name<BR> wc.lpszClassName = FadeBarClassName;<BR> //we don't have to worry about h or v redraws<BR> //alloc a DC for each instance and keep it until destruction<BR> //saves on all the Get/Release DC BS during painting<BR> wc.style = CS_OWNDC;<BR> //set the instance<BR> wc.hInstance = hInstance;<BR> if (RegisterClassEx(&wc))<BR> return TRUE;<BR> return FALSE;<BR> void UnregisterFadeBar (HINSTANCE hInstance) {<BR> UnregisterClass (FadeBarClassName, HInstance);<BR> } fadebar.h<BR> &num ifndef _FADEBAR_H_<BR> &num define _FADEBAR_H_<BR> &num define WM_FBSETLCOLOR WM_USER+1<BR> &num define WM_FBSETLCOLOR WM_FBSETLCOLOR+1<BR> &num define WM_FBSETLCOLOR WM_FBSETLCOLOR+1<BR> &num define WM_FBSETLCOLOR WM_FBSETLCOLOR+1<BR> &num define WM_FBSETMODE WM_FBSETLCOLOR+1<BR> &num define FBM_INACTIVE 0<BR> &num define FBM_RGB 1<BR> &num define FBM_HSV 2<BR> &num define FadeBarClassName "WCFadeBar"<BR> &num ifdef _cplusplus<BR> extern "C" {<BR> &num endif //_cplusplus<BR> BOOL REgisterFadeBar (HINSTANCE hInstance);<BR> void unRegisterFadeBar (HINSTANCE hInstance);<BR> &num ifdef _cuplusplus<BR> }<BR> &num endif //_cplusplus<BR> &num endif //_FADEBAR_H_<BR> /*** End of file: fadebar.h ***/ cellvue.h<BR> &num ifndef _CELLVUE_H_<BR> &num define _CELLVUE_H_<BR> &num ifdef _cplusplus<BR> extern "C" {<BR> &num endif<BR> // import/export macro so both cellvue and plugins<BR> // can include the same .h files<BR> &num ifndef APSAPI<BR> &num ifdef COMPILING_CELLVUE_APP<BR> &num define APSAPI _declspec(dllexport)<BR> &num else<BR> &num define APSAPI _declspec(dllimport)<BR> &num endif<BR> &num endif<BR> /*********************************************************************<BR> ********/<BR> // messages valid range is WM_USER (1024) to 32768<BR> enum _APSWMENUMS<BR> {<BR> WM_APS_INIT = WM_USER + 5001,<BR> // sent to<BR> all plugin main message handlers just after load<BR> WM_APS_CONSTRUCTOR,<BR> //<BR> tell plugin toi create an instance<BR> WM_APS_NEW_DATASET_LOADED,<BR> // sent to<BR> all plugin *instances* when a new dataset is opened<BR> WM_APS_REQUEST_CUBE, cellvue.h<BR> // request a<BR> 3d cube<BR> WM_APS_CUBE_PACKET,<BR> //<BR> new cube data<BR> WM_APS_REQUEST_SLICE,<BR> // request a<BR> 2d slice<BR> WM_APS_SLICE_PACKET,<BR> // new slice<BR> WM_APS_SET_ANTS_X,<BR> //<BR> sent to all plugin *instances* when crop region changes so they can up<BR> date their own views<BR> WM_APS_SET_ANTS_Y,<BR> // "<BR> WM_APS_SET_ANTS_Z,<BR> // "<BR> WM_APS_CANCEL_LOAD,<BR> //<BR> sent to all plugins from input plugin when load fails<BR> WM_APS_BRIGHTFIELD_MODE,<BR> //sent to<BR> all plugins when going to/from brightfield mode<BR> WM_APS_CMDLINE, cellvue.h<BR> //sent to all plugins if there is a command line to share<BR> WM_APS_SET_ANTS_3D_X,<BR> // sent from<BR> 2d to 3d plugin when the ants region changes<BR> WM_APS_SET_ANTS_3D_Y,<BR> // "<BR> WM_APS_SET_ANTS_3D_Z,<BR> // "<BR> WM_APS_REDRAW_3D,<BR> //<BR> force 3d plugin to rerender<BR> WM_APS_DISABLE_ANTS_DRAGGING,<BR> // tell 2d win to<BR> not let user drag ants<BR> WM_APS_ENABLE_ANTS_DRAGGING,<BR> // let user drag<BR> ants again<BR> WM_APS_CONFINE_ANTS_X,<BR> // message<BR> from 3d > 2d to confine ants region<BR> WM_APS_CONFINE_ANTS_Y,<BR> WM_APS_CONFINE_ANTS_Z,<BR> WM_APS_TAB_LOSE_FOCUS,<BR> // sent to a<BR> tab dialog proc when user selects new tab celvue.h<BR> WM_APS_TAB_GAIN_FOCUS,<BR> WM_APS_GETDSVARVAL,<BR> //sent only to input plugin lookup the<BR> //value associated w/ a var (WPARAM) from the<BR> //dataset string table. the const char * is returned<BR> //in a char ** (LPARAM)<BR> };<BR> // keyboard accelerator messages (look in cellvue.rc)<BR> &num define IDM_FULLSCREEN 1<BR> &num define IDM_SHOWPLUGINS 2 cellvue.h<BR> /*********************************************************************<BR> *******/<BR> // defines<BR> // fixed point math<BR> typedef unsigned long FIXEDPOINT;<BR> &num define FIXEDPLACES 14 // number of places that wi<BR> 11 be used for the "remainder" portion (was<BR> 15)<BR> &num define FIXEDPOWER ( 1#FIXEDPLACES )<BR> &num define FIXEDRMDMASK ( (1#FIXEDPLACES) 1 )<BR> &num define INT2FIXED(a) ( ((unsigned long) (a))#FIXEDP<BR> LACES )<BR> &num define FLOAT2FIXED(a) ( (unsigned long) ( ((double) (a))*((dou<BR> ble)FIXEDPOWER) ) )<BR> &num define FIXEDMULINT(a,b) ( (a)*(b) )<BR> &num define FIXEDMUL(a,b) ( ((a)*(b)) # FIXEDPLACES )<BR> &num define FIXEDRMD(a) ( (a) & FIXEDRMDMASK )<BR> &num define FIXED2INT(a) ( (a) # FIXEDPLACES )<BR> &num define FIXED2FLOAT(a) ( ((double)(a)) / ((double)FIX<BR> EDPOWER) )<BR> &num define FIXED2IDX(a,bits) ( ( (a) # (FIXEDPLACES (bits)<BR> ) ) & ((1#(bits))1) )<BR> // put tabs on top instead bottom<BR> &num define TABS_ON_TOP 1<BR> // min color depth required<BR> &num define MIN_COLOR_DEPTH 15<BR> // minimum window size for main window cellvue.h<BR> &num define MIN_APP_WIDTH 1024<BR> &num define MIN_APP_HEIGHT 768<BR> // hardcoded size of the 3d window<BR> &num define _3D_VIEW_W 362<BR> &num define _3D_VIEW_H 362<BR> // id of any tab control<BR> &num define IDC_APSTABCTL 4096<BR> // flags for APSCUBE's RGBFlags<BR> &num define RGBFLAGS_RED 0x0001<BR> &num define RGBFLAGS_GREEN 0x0002<BR> &num define RGBFLAGS_BLUE 0x0004<BR> &num define RGBFLAGS_AUX 0x0008<BR> &num define CUBE_8BIT_COLOR 0x0010 //cube is 8 bit paletted color<BR> volume<BR> &num define CUBE_16BIT_COLOR 0x0020 //cube is 16 rgb bit color volu<BR> me (4 bits x rgba?)<BR> &num define CUBE_24BIT_COLOR 0x0040 //cube is 24 rgb bit color volu<BR> me<BR> &num define CUBE_32BIT_COLOR 0x0080 //cube is rgba color volume<BR> //barring any of above, cube is 8 bit mono volume<BR> // plugin flags<BR> &num define PLUGFLAGS_LUT_CONVERTED 0x0001<BR> // internal used only by<BR> apslut<BR> &num define PLUGFLAGS_ENHANCED 0x0002<BR> // internal used only by<BR> apsenh cellvue.h<BR> /*********************************************************************<BR> *******/<BR> // structures<BR> // color struct (for win32)<BR> typedef struct _APSCOLOR<BR> {<BR> BYTE b;<BR> BYTE g;<BR> BYTE r;<BR> BYTE a;<BR> // not used<BR> } APSCOLOR, *LPAPSCOLOR;<BR> // slice request/return structure cellvue.h<BR> typedef struct _APSSLICE<BR> {<BR> DWORD dwPacketID;<BR> CHAR cAxis; // par<BR> am 'x', 'y', 'z'<BR> LONG dwDepth; // par<BR> am<BR> LONG x1, y1, x2, y2; // exparams<BR> DWORD dwWidth;<BR> DWORD dwHeight;<BR> DWORD dwChannels;<BR> DWORD dwRGBFlags;<BR> DWORD dwBitsPerPixel;<BR> DWORD dwFlags;<BR> BITMAPINFO bmi; // windows<BR> bitmap info (why not have it here too, eh?)<BR> DWORD channel_masks_dummy[2]; // needed for b&w do no<BR> t remove order!<BR> LPAPSCOLOR psData;<BR> DWORD dwReserved1;<BR> DWORD dwReserved2;<BR> DWORD dwReserved3;<BR> } APSSLICE, *LPAPSSLICE; cellvue.h<BR> // generic "cube" structure used to pass 3D requests and returns<BR> typedef struct _APSCUBE<BR> {<BR> DWORD dwPacket ID;<BR> DWORD dwRefCount;<BR> //<BR> reference count<BR> DWORD x1, y1, z1;<BR> //<BR> param (all 0's to specify full dataset)<BR> DWORD x2, y2, z2;<BR> //<BR> param (all 0's to specify full dataset)<BR> double rmult, gmult, bmult;<BR> // param (channel<BR> math multipliers)<BR> DWORD dwFitInCubeSize;<BR> // param (fit<BR> resultant voxels in a cube of n*n*n)<BR> DWORD dwSmpWidth, dwSmpHeight, dwSmpDepth; cellvue.h<BR> // dimensions of full smp file<BR> DWORD dwWidth, dwHeight, dwDepth;<BR> // dimenasions of<BR> loaded cube data<BR> DWORD dwChannels;<BR> //<BR> channels in the big file (not in the cube)<BR> DWORD dwStartz, dwStopZ;<BR> // new region that's<BR> just been added<BR> DWORD dwFlags;<BR> LPBYTE pbVoxels;<BR> //<BR> raw voxels<BR> LPBYTE pbPhongs;<BR> //<BR> shaded surface<BR> LPBYTE pbSeg;<BR> //<BR> segmentaiton buffer<BR> APSCOLOR *pspalette;<BR> //<BR> color palette for 8 bit color volumes<BR> DWORD dwReserved1;<BR> DWORD dwReserved2;<BR> DWORD dwReserved3;<BR> } APSCUBE, *LPAPSCUBE; celluvie.h externs //externs //externs extern APSAPI DWORD dwExpired ; extern APSAPI BYTE szAppPath []; extern APSAPI BYTE szPluginPath [] ; extern APSAPI BYTE szDatasetPath [] ; extern APSAPI BYTE szDatasetName []; extern APSAPI INSTANCE hAppInstance ; extern APSAPI HWND hAppWnd ; extern APSAPI HIND h2DWnd; extern APSAPI HWND h3DWnd ; extern APSAPI HWND hUtilWnd ; extern HWND hRightSplitter ; extern HWND hMainSplitter ; cellvue.h<BR> extern HWND hBottomTabHolder;<BR> extern HWND hBottomTabCtr1;<BR> extern APSAPI BOOL dwRenderingHires;<BR> extern APSAPI BOOL dwCloseAfterHires;<BR> extern APSAPI DWORD dwDatasetWidth;<BR> extern APSAPI DWORD dwDatasetHeight;<BR> extern APSAPI DWORD dwDatasetDepth;<BR> /*********************************************************************<BR> ********/<BR> // prototypes<BR> // splash.c<BR> int SplashScreen( int time );<BR> // expire.c<BR> int CheckExpire();<BR> // inviswnd.c<BR> HWND apsInvisCreateWindow();<BR> // 2dwnd.c<BR> HWND aps2DCreateWindow();<BR> // 3dwnd.c<BR> HWND aps3DCreateWindow(); cellvue.h // utilwnd.c<BR> HWND apsUtilCreatewindow();<BR> // dlghold.c<BR> HWND apsDlgHolderCreateWindow();<BR> // htabhold.c<BR> HWND apsHTabHolderCreateWindow();<BR> // vtabhold.c<BR> HWND apsVTabHolderCreateWindow();<BR> // router.c<BR> VOID InitRouting();<BR> APSAPI VOID RequestOrthoSlice( CHAR cAxis, LONG dw<BR> Depth, HWND hInstWnd );<BR> APSAPI VOID RequestOrthoSliceEx( CHAR cAxis, LONG<BR> dwDepth, LONG x1, LONG y1, LONG x2, LONG y2,<BR> HWND hInstWnd );<BR> APSAPI VOID ProduceOrtheSlice( LPAPSSLICE psSlice,<BR> Page 7 cellvue.h<BR> HWND hInstWnd );<BR> APSAPI LPAPSSLICE DuplicateOrthoSlice( LPAPSSLICE psSlice );<BR> APSAPI VOID DestroyOrthoSlice( LPAPSSLICE psSlice<BR> );<BR> APSAPI VOID RequestCube( LONG x1, LONG x2, LONG y1, LONG<BR> y2, LONG z1, LONG z2, double rmult, double<BR> gmult, double bmult, LONG dwFitInCubeSize, HWND hInstWnd );<BR> APSAPI VOID ProduceCube( LPAPSCUBE psCube, HWND hI<BR> nstWnd );<BR> APSAPI VOID DestroyCube( LPAPSCUBE psCube );<BR> APSAPI LONG RefIncCube( LPAPSCUBE psCube );<BR> APSAPI LONG RefDecCube( LPAPSCUBE psCube );<BR> APSAPI VOID SendMessageToAllPluginInstances( UINT Msg, WPARAM<BR> wParam, LPARAM lParam ); cellvue.h<BR> // apsmisc.c<BR> APSAPI LPBYTE apsmalloc( DWORD dwNumBytes );<BR> APSAPI LPBYTE apsmalloc0( DWORD dwNumBytes );<BR> APSAPI VOID apsfree( LPVOID pbMem );<BR> APSAPI LPSTR StrSave( LPSTR szStringToCopy );<BR> APSAPI LPSTR NameOnly( LPSTR szFileName );<BR> APSAPI VOID Rect2Pos( LPRECT psRect );<BR> APSAPI VOID RectFromPos( LPRECT psRect, LPRECT psSource );<BR> APSAPI VOID Pos2Rect( LPRECT psRect );<BR> APSAPI BOOL PosInRect( LONG xPos, LONG yPos, LPRECT psRect<BR> );<BR> APSAPI BOOL SetWindowRect( HWND hWnd, HWND hWndInsertAfter<BR> , LPRECT psRect, UINT uFlags );<BR> APSAPI VOID ClipRect( LPRECT psClientRect, LPRECT psParent<BR> Rect );<BR> APSAPI VOID MergeRects( LPRECT psRect, LPRECT psRect1, LPR<BR> ECT psRect2 );<BR> APSAPI BOOL NormalizeRect( LPRECT pSRect );<BR> APSAPI VOID ZoomRect( LPRECT psDest. LPRECT psSource, doub<BR> le fZoom );<BR> APSAPI VOID UnzoomRect( LPRECT psDest, LPRECT psSource, do<BR> uble fZoom );<BR> APSAPI VOID StretchChildToFitParent( HWND hParent );<BR> APSAPI VOID StretchChildrenToFitParent( HWND hParent );<BR> APSAPI VOID DrawBitmap( HDC hdc, HBITMAP hBitmap, int xSta<BR> rt, int yStart );<BR> APSAPI VOID winprintf( HDC hdc, int x, int y, char *sz, ... );<BR> APSAPI HWND createListboxWindow( LPSTR szTitle, DWORD dwLe<BR> ft, DWORD dwTop, DWORD dwWidth, DWORD<BR> dwHeight, HWND hParent );<BR> APSAPI VOID printfListbox( HWND hWnd, LPSTR szMessage, ...<BR> <P>);<BR> APSAPI VOID apsErrBox( LPSTR szMessage, ... );<BR> APSAPI LPDWORD AllocRGBDIB( HDC* phdc, HBITMAP* phbmp, int w, int h,<BR> HDC usedc );<BR> APSAPI VOID FreeRGBDIB( HDC* hdc, HBITMAP* hbmp ); cellvue.h<BR> APSAPI VOID CheckWindowsMessages();<BR> &num ifdef_cplusplus<BR> }<BR> &num endif<BR> &num endif<BR> /*** End of file: cellvue.h ***/ 1.
2. An image production method comprising: a) staining a sample with a fluorescent dye; b) producing a first image of the resultant fluorescentdyed 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 nonfluorescent dye.
3. The method of claim 1, wherein said first image is produced using a blockface microscope.
4. 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.
5. The method of claim 1, wherein said sample is stained with at least two fluorescent dyes.
6. The method of claim 1, wherein said sample is a biological sample.
7. 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.
8. The method of claim 6, wherein said first and second images are produced using a blockface microscope.
9. An image production method comprising: 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.
10. The method of claim 8, wherein said first and second images are produced using a blockface microscope.
11. The method of claim 8, wherein said dye comprises a metachromatic dye.
12. The method of claim 10, wherein said metachromatic dye comprises acridine orange.
13. 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 nonfluorescent dye.
14. The method of claim 12, wherein said first image is produced using a blockface microscope.
15. 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.
16. The method of claim 14, wherein said first image is produced using a blockface microscope.
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 fluorochromes, 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/maxsamplevalue (e. g., 8-bit = 255) where I is the index of the current lookup table value being calculated, and ranges from 0 to maxsamplevalue (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 maxsamplevalue (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: maxsamplevalue-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/maxsamplevalue (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 maxsamplevalue). 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 Exan2ple 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 = 2A10 = 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 Metliod 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 producirig 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: