~ubuntu-branches/ubuntu/utopic/mricron/utopic

1 by Michael Hanke
Import upstream version 0.20100725.1~dfsg.1
1
unit autoroi;
2
3
interface
4
5
uses
6
 {$IFNDEF FPC}
7
 RXSpin,capmenu,
8
 {$ELSE}
9
 Spin,lResources,
10
 {$ENDIF}
11
 {$IFNDEF Unix} Windows,{$ENDIF}
12
 SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
13
  Buttons, StdCtrls, define_types, ExtCtrls, nifti_img,nifti_img_view;
14
15
type
16
17
  { TAutoROIForm }
18
19
  TAutoROIForm = class(TForm)
20
    OriginLabel: TLabel;
21
    OriginBtn: TSpeedButton;
22
    EdgeEdit: TSpinEdit;
23
    RadiusEdit: TSpinEdit;
24
    ErodeEdit: TSpinEdit;
25
    ROIconstraint: TComboBox;
26
    VarianceEdit: TSpinEdit;
27
    DiffLabel: TLabel;
28
    Label1: TLabel;
29
    Label2: TLabel;
30
    Label3: TLabel;
31
    AutoROIBtn: TSpeedButton;
32
    CancelBtn: TSpeedButton;
33
    Timer1: TTimer;
34
    Label4: TLabel;
35
    ExcludeBlackCheck: TCheckBox;
36
	procedure OriginBtnClick(Sender: TObject);
37
	procedure PreviewBtnClick(Sender: TObject);
38
	procedure FormShow(Sender: TObject);
39
	procedure FormCreate(Sender: TObject);
40
	procedure FormHide(Sender: TObject);
41
	procedure AutoROIBtnClick(Sender: TObject);
42
	procedure CancelBtnClick(Sender: TObject);
43
	procedure AutoROIchange(Sender: TObject);
44
	procedure Timer1Timer(Sender: TObject);
45
	procedure FormDestroy(Sender: TObject);
46
  private
47
	{ Private declarations }
48
  public
49
	{ Public declarations }
50
  end;
51
52
procedure ROICluster ({lInROIBuf: bytep;} lXdim, lYDim, lZDim,lXOriginIn,lYOrigin,lZOrigin: integer; lDeleteNotFill: boolean);
53
var
54
  AutoROIForm: TAutoROIForm;
55
  gOriginX,gOriginY,gOriginZ: integer;
56
implementation
57
58
 {$IFNDEF FPC}
59
 {$R *.DFM}
60
 {$ENDIF}
61
62
63
procedure TAutoROIForm.OriginBtnClick(Sender: TObject);
64
begin
65
 gOriginX := ImgForm.XViewEdit.value;
66
 gOriginY := ImgForm.YViewEdit.value;
67
 gOriginZ := ImgForm.ZViewEdit.value;
68
 OriginLabel.Caption := 'Origin: '+inttostr(gOriginX)+'x'+inttostr(gOriginY)+'x'+inttostr(gOriginZ);
69
 PreviewBtnClick(sender);
70
end;
71
72
procedure TAutoROIForm.PreviewBtnClick(Sender: TObject);
73
var
74
   lXmm,lYmm,lZmm,lSqrRadius: single;
75
   lExcludeBlackIfZero,//lX,lY,lZ, //abba
76
   {lMaxROISz,}lEdge,lOriginPos,lROISz,lOriginIntensity,lVariance,lXdim, lYDim, lZDim: integer;
77
   lErodeCycles,lQTail,lQHead,lSliceSz,lQSz,lInc,lVolSz{,lX,lY,lZ}: integer;
78
   lROIConstrain,lReadFilteredData: boolean;
79
   lQra: LongIntP;
80
   lSourceBuffer,lBuff,lPreErodeBuff: ByteP;
81
const
82
	 kFillValue = -2;
83
Procedure IncQra(var lVal, lQSz: integer);
84
begin
85
	inc(lVal);
86
	if lVal >= lQSz then
87
	 lVal := 1;
88
end;
89
function UnsmoothedIntensity(lPixel: integer): integer; //1381
90
begin
91
	  if lReadFilteredData then
92
		 result := lBuff^[lPixel]
93
	  else
94
		  Result :=lSourceBuffer^[lPixel];
95
end;
96
97
 function MeanIntensity(lPixel: integer): integer;
98
 var lV: integer;
99
 begin
100
	  if lReadFilteredData then
101
		 result := lBuff^[lPixel]
102
	  else if ((lPixel-lSliceSz) > 0) and ((lPixel+lSliceSz) <= lVolSz) then begin
103
		 lV :=lSourceBuffer^[lPixel]+lSourceBuffer^[lPixel+1]+lSourceBuffer^[lPixel-1] //L/R
104
			+lSourceBuffer^[lPixel+lXdim]+lSourceBuffer^[lPixel-lXdim] //Anterior/Posterior
105
			+lSourceBuffer^[lPixel+lSliceSz]+lSourceBuffer^[lPixel-lSliceSz]; //Dorsal/Ventral
106
		 result := lV div 7;
107
	  end else result := lSourceBuffer^[lPixel];//1401 gImageBackupBuffer[lPixel]
108
 end;
109
 procedure Check(lPixel,lIntensity: integer);
110
 var lSmoothInten :integer;
111
 begin
112
   lSmoothInten := MeanIntensity(lPixel);
113
   if (lROIConstrain) and (gBGImg.VOIUndoVol^[lPixel] > 0) then //1410
114
	 //constrain
115
   else if (lBuff^[lPixel]<> 255) and (UnsmoothedIntensity(lPixel) > lExcludeBlackIfZero {1381}) and  (abs(lSmoothInten-lIntensity)<=lEdge) and(abs(lSmoothInten-lOriginIntensity)<=lVariance) {}then begin//add item
116
		incQra(lQHead,lQSz);
117
		inc(lROISz);
118
		lBuff^[lPixel] := 255;
119
		lQra^[lQHead] := lPixel;
120
   end;
121
 end;
122
123
PROCEDURE RetirePixel; //FIFO cleanup
124
function WithinRadius(lXs,lYs,lZs:integer): boolean;
125
begin
126
	 if (sqr((lXs-gOriginX)*lXmm)+sqr((lYs-gOriginY)*lYmm)+sqr((lZs-gOriginZ)*lZmm)) > lSqrRadius then
127
		result := false
128
	 else
129
		 result := true;
130
end;
131
VAR
132
   lVal,lXPos,lYPos,lZPos,lIntensity: integer;
133
BEGIN
134
   lVal := lQra^[lQTail];
135
   lXpos := lVal mod lXdim;
136
   if lXpos = 0 then lXPos := lXdim;
137
138
   lYpos := (1+((lVal-1) div lXdim)) mod lYDim;
139
   if lYPos = 0 then lYPos := lYdim;
140
141
   lZpos := ((lVal-1) div lSliceSz)+1;
142
   if lReadFilteredData then
143
	  lIntensity := 128
144
   else
145
	   lIntensity := lSourceBuffer^[lVal];//1401 gImageBackupBuffer[lVal];
146
   if (lXpos > 1) and WithinRadius(lXpos-1,lYpos,lZpos) then Check(lVal -1,lIntensity);//check to left
147
   if (lXPos < lXDim) and (WithinRadius(lXpos+1,lYpos,lZpos)) then Check(lVal + 1,lIntensity); //check to right
148
   if (lYpos > 1) and (WithinRadius(lXpos,lYpos-1,lZpos)) then Check(lVal -lXdim,lIntensity);//check previous line
149
   if (lYPos < lYDim) and (WithinRadius(lXpos,lYpos+1,lZpos)) then Check(lVal + lXdim,lIntensity); //check next line
150
   if (lZpos > 1) and (WithinRadius(lXpos,lYpos,lZpos-1)) then Check(lVal -lSliceSz,lIntensity);//check previous slice
151
   if (lZPos < lZDim) and (WithinRadius(lXpos,lYpos,lZpos+1)) then Check(lVal + lSliceSz,lIntensity); //check next slice
152
   incQra(lQTail,lQSz); //done with this pixel
153
END;
154
155
procedure FillStart (lPt: integer); {FIFO algorithm: keep memory VERY low}
156
var lI: integer;
157
begin
158
  for lI := 1 to lQsz do
159
	  lQra^[lI] := 0;
160
  lQHead := 0;
161
  lQTail := 1;
162
  lROISz := 0;
163
  Check(lPt,lOriginIntensity);
164
  RetirePixel;
165
  while ((lQHead+1) <> lQTail) do begin//complete until all voxels in buffer have been tested
166
		RetirePixel;
167
		if (lQHead = lQSz) and (lQTail = 1) then
168
		   exit; //break condition: avoids possible infinite loop where QTail is being incremented but QHead is stuck at maximum value
169
  end;
170
end;
171
172
function ROIOnEdge (lVal: integer): boolean;
173
BEGIN
174
   result := false;
175
   if lBuff^[lVal] <> 255 then exit; //not ROI - is not boundary
176
   //Find
177
   if ((lVal-lSliceSz) > 0) and ((lVal+lSliceSz) <= lVolSz) then begin
178
			if lBuff^[lVal+1] = 0 then result := true;
179
			if lBuff^[lVal-1] = 0 then result := true;
180
			if lBuff^[lVal+lXdim] = 0 then result := true;
181
			if lBuff^[lVal-lXdim] = 0 then result := true;
182
			if lBuff^[lVal+lSliceSz] = 0 then result := true;
183
			if lBuff^[lVal-lSliceSz] = 0 then result := true;
184
   end;
185
end;
186
187
function ZeroOnEdge (lVal: integer): boolean;
188
BEGIN
189
   result := false;
190
   if lBuff^[lVal] <> 0 then exit; //not ROI - is not boundary
191
   //Find
192
   if ((lVal-lSliceSz) > 0) and ((lVal+lSliceSz) <= lVolSz) then begin
193
			if lBuff^[lVal+1] = 255 then result := true;
194
			if lBuff^[lVal-1] = 255 then result := true;
195
			if lBuff^[lVal+lXdim] = 255 then result := true;
196
			if lBuff^[lVal-lXdim] = 255 then result := true;
197
			if lBuff^[lVal+lSliceSz] = 255 then result := true;
198
			if lBuff^[lVal-lSliceSz] = 255 then result := true;
199
   end;
200
end;
201
202
begin                                                       //alfa666
203
	 if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<1) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<>gBGImg.VOIUndoVolItems) then exit;
204
	 //if gImageBackupSz <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems then
205
	 //UpdateBackupBuffer;
206
	 lXdim := gBGImg.ScrnDim[1];
207
	 lYDim := gBGImg.ScrnDim[2];
208
	 lZDim := gBGImg.ScrnDim[3];
209
	 if (gBGImg.Scrnmm[1] = 0) or (gBGImg.Scrnmm[2]=0) or (gBGImg.Scrnmm[3]=0) then begin
210
		 lXmm := 1;
211
		 lYmm := 1;
212
		 lZmm := 1;
213
	 end else begin
214
		 lXmm := gBGImg.Scrnmm[1];
215
		 lYmm := gBGImg.Scrnmm[2];
216
		 lZmm := gBGImg.Scrnmm[3];
217
	 end;
218
	 lSliceSz := lXdim * lYdim;
219
	 lVolSz := lSliceSz*lZdim;
220
	 //lMaxROISz := round(PctImg.Value/100 * lVolSz);
221
	 lOriginPos := gOriginX + ((gOriginY-1)*lXdim) + ((gOriginZ-1)*lSliceSz);
222
	 if (lOriginPos < 1) or (lVolSz <> gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems) or (lOriginPos > lVolSz) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems <> gBGImg.VOIUndoVolItems) then
223
		exit;
224
         {$IFNDEF FPC}
225
	 lVariance := AutoROIForm.VarianceEdit.asinteger; //asinteger;
226
	 lEdge := AutoROIForm.EdgeEdit.asinteger;
227
         lSqrRadius := sqr(AutoROIForm.RadiusEdit.asinteger);
228
         {$ELSE}
229
	 lVariance := AutoROIForm.VarianceEdit.value; //asinteger;
230
	 lEdge := AutoROIForm.EdgeEdit.value;
231
         lSqrRadius := sqr(AutoROIForm.RadiusEdit.value);
232
         {$ENDIF}
233
	 if (lXDim < 4) or (lYDim < 4) or (lZDim < 4) or (lVolSz < 1)  then exit;
234
	 lSourceBuffer := gMRIcroOverlay[kBGOverlayNum].ScrnBuffer;//gBuffer;
235
	 //Next - START count cluster size
236
	 lQSz := (lVolSz div 4)+8;
237
	 GetMem(lQra,lQsz * sizeof(longint) );
238
	 //check positive clusters....
239
	 Getmem(lBuff,lVolSz);
240
	 FillChar(lBuff^,lVolSz, 0);
241
	 //Move(gImageBackupBuffer^,lBuff^,lVolSz);
242
	 if ExcludeBlackCheck.checked then //1381
243
	   lExcludeBlackIfZero := 0 //0
244
	 else
245
		 lExcludeBlackIfZero := -1;//impossible 8-bit value: do not use this feature
246
	 lOriginIntensity := lSourceBuffer^[lOriginPos]; //1401 gImageBackupBuffer[lOriginPos];
247
	 lReadFilteredData := false;
248
	 //ROIconstrainCheck.enabled := (gROIBupSz > 1); //1410: next 3 lines
249
	 ROIconstraint.enabled := (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 1); //1410: next 3 lines
250
	 if (ROIconstraint.ItemIndex = 2) and (ROIconstraint.enabled) then
251
		lROIConstrain := true
252
	 else
253
		 lROIconstrain := false;
254
	 FillStart(lOriginPos);
255
	 lROIConstrain := false;//1410
256
	 //START: ERODE/DILATE CYCLES
257
{$IFNDEF FPC}
258
	 lErodeCycles :=  AutoROIForm.ErodeEdit.asinteger;
259
{$ELSE}
260
	 lErodeCycles :=  AutoROIForm.ErodeEdit.value;
261
{$ENDIF}
262
	 if lErodeCycles > 0 then begin
263
		Getmem(lPreErodeBuff,lVolSz);
264
		Move(lBuff^,lPreErodeBuff^,lVolSz);
265
		for lQHead := 1 to lErodeCycles do begin//ERODE
266
			for lInc := 1 to lVolSz do
267
				if ROIonEdge(lInc) then
268
				   lBuff^[lInc] :=254;
269
			for lInc := 1 to lVolSz do
270
				if lBuff^[lInc]=254 then
271
				   lBuff^[lInc] := 0; //erode
272
		end;//for ErodeCycles = ERODE
273
		//SET ALL VOXELS THAT HAVE SURVIVED EROSION TO 128, WE THEN GROW THE ORIGIN
274
		for lInc := 1 to lVolSz do
275
			if lBuff^[lInc] =255 then lBuff^[lInc] := 128;
276
		//NOW - ONLY PRESERVE STUFF CONNECTED TO ORIGIN
277
		lBuff^[lOriginPos] := 128;
278
		lOriginIntensity := 128;
279
		lVariance := 2;
280
		lEdge := 2;
281
		lReadFilteredData := true;
282
		FillStart(lOriginPos);
283
		//SWITCH OFF ALL UNCONNECTED BLOBS
284
		for lInc := 1 to lVolSz do
285
			if lBuff^[lInc] =128 then lBuff^[lInc] := 0;
286
		//for lInc := 1 to lVolSz do
287
		//    if lBuff[lInc] > 0 then showmessage(inttostr(lBuff[lInc]));// := 0;
288
289
		for lQHead := 1 to lErodeCycles do begin//DILATE
290
			for lInc := 1 to lVolSz do
291
				if (lPreErodeBuff^[lInc] = 255) and (ZeroonEdge(lInc)) then
292
				   lBuff^[lInc] :=254;
293
			for lInc := 1 to lVolSz do
294
				if lBuff^[lInc]=254 then
295
				   lBuff^[lInc] := 255; //erode
296
		end;//for ErodeCycles = DILATE
297
	  Freemem(lPreErodeBuff);
298
	  {}
299
	 end; //ERODE cycles > 0
300
	 //END: ERODE/DILATE
301
	 Freemem(lQra);
302
	 ROIconstraint.enabled := (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 1); //1410: next 3 lines
303
	 if (ROIconstraint.ItemIndex = 1) and (ROIconstraint.enabled) then begin //delete ROI
304
		for lInc := 1 to gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems do //gROIBup
305
			if (lBuff^[lInc] = 255) then
306
			   lBuff^[lInc] := 0
307
			else
308
			   lBuff^[lInc] := gBGImg.VOIUndoVol^[lInc];
309
	 end else (*if true {alfa (gDynSz > 1) and (gROIBupsz > 1) {and (gImageBackupSz = gDynSz){} then begin
310
		for lInc := 1 to gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems do
311
			if lBuff[lInc] = 255 then
312
			else if gImageBackupBuffer[lInc] = 255 then
313
				 lBuff[lInc] := 255//255;
314
			else lBuff[lInc] := lSourceBuffer[lInc];
315
316
	 end else *)
317
	   for lInc := 1 to lVolSz do
318
		 if lBuff^[lInc] <> 255 then
319
			lBuff^[lInc] := gBGImg.VOIUndoVol^[lInc]
320
		 else
321
			lBuff^[lInc] := kVOI8bit;//1401 gImageBackupBuffer[lInc];
322
	 Move(lBuff^,gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,lVolSz);
323
	 Freemem(lBuff);
324
	 //END check clusters
325
	 ImgForm.RefreshImagesTimer.Enabled := true;
326
end;
327
328
procedure TAutoROIForm.FormShow(Sender: TObject);
329
begin
330
EnsureVOIOpen;
331
CreateUndoVol;
332
	AutoROIForm.ModalResult := mrCancel;
333
	ROIconstraint.Enabled := (gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 1);
334
	OriginBtn.OnClick(sender);
335
	 //DeleteCheck.enabled := (gROIBupSz > 1);
336
	 //ROIConstrainCheck.enabled := (gROIBupSz > 1);
337
end;
338
339
procedure TAutoROIForm.FormCreate(Sender: TObject);
340
begin
341
 {$IFNDEF FPC}
342
	 ROIconstraint.SetItemIndex(0);//1410
343
 {$ELSE}
344
	 ROIconstraint.ItemIndex := (0);//1410
345
 {$ENDIF}
346
end;
347
348
procedure TAutoROIForm.FormHide(Sender: TObject);
349
begin
350
//	 if (AutoROIForm.ModalResult = mrCancel) and (gBGImg.VOIUndoVolItems > 1) and (gBGImg.VOIUndoVolItems = gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems) then
351
//		Move(gImageBackupBuffer^,gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,gImageBackupSz);
352
	 if (AutoROIForm.ModalResult = mrCancel) then
353
		UndoVolVOI;
354
	 if not (AutoROIForm.ModalResult = mrCancel) then
355
		gBGImg.VOIchanged := true;
356
	 //if gImageBackupSz <> 0 then Freemem(gImageBackupBuffer);
357
	 //gImageBackupSz := 0;
358
	 ImgForm.Fill3DBtn.Down := false;
359
	 ImgForm.RefreshImagesTimer.Enabled := true;
360
end;
361
362
//Previous: create 3D ROI
363
//Below fill bubbles in 3D ROIS
364
//ROIcluster Follows
365
(***********************************************************88
366
************************************************************
367
**********************************************************)
368
procedure ROICluster (lXdim, lYDim, lZDim,lXOriginIn,lYOrigin,lZOrigin: integer; lDeleteNotFill: boolean);
369
var
370
  lVariability,lOrigin,lClusterInputValue,lClusterOutputValue, lClusterSz,lQTail,
371
  lXOrigin,lQHead,lSliceSz,lQSz,lInc,lVolSz: integer;
372
  lXInc,lYInc,lZInc,lSlicePos,lYPos,
373
  lMinX,lMaxX,lMinY,lMaxY,lMinZ,lMaxZ,
374
  lMinXBound,lMaxXBound,lMinYBound,lMaxYBound,lMinZBound,lMaxZBound: integer;
375
  lAtEdge: boolean;
376
  lROIBuf: bytep;
377
  lQra: LongIntP;
378
const
379
     kFillValue = -2;
380
Procedure IncQra(var lVal, lQSz: integer);
381
begin
382
    inc(lVal);
383
    if lVal >= lQSz then
384
     lVal := 1;
385
end;
386
387
 procedure Check(lPixel: integer);
388
 begin
389
    if (abs(lROIBuf^[lPixel] - lClusterInputValue)) <= lVariability then begin//add item
390
        incQra(lQHead,lQSz);
391
        inc(lClusterSz);
392
		lROIBuf^[lPixel] := lClusterOutputValue;
393
        lQra^[lQHead] := lPixel;
394
   end;
395
 end;
396
397
PROCEDURE RetirePixel; //FIFO cleanup
398
VAR
399
   lVal,lXPos,lYPos,lZPos: integer;
400
BEGIN
401
   lVal := lQra^[lQTail];
402
   lXpos := lVal mod lXdim;
403
   if lXpos = 0 then lXPos := lXdim;
404
405
   lYpos := (1+((lVal-1) div lXdim)) mod lYDim;
406
   if lYPos = 0 then lYPos := lYdim;
407
408
   lZpos := ((lVal-1) div lSliceSz)+1;
409
410
   if lXPos < lMinX then lMinX := lXPos;
411
   if lXPos > lMaxX then lMaxX := lXPos;
412
   if lXpos > lMinXBound then Check(lVal -1);//check to left
413
   if lXPos < lMaxXBound then Check(lVal + 1); //check to right
414
415
   if lYPos < lMinY then lMinY := lYPos;
416
   if lYPos > lMaxY then lMaxY := lYPos;
417
   if lYpos > lMinYBound then Check(lVal -lXdim);//check previous line
418
   if lYPos < lMaxYBound then Check(lVal + lXdim); //check next line
419
420
   if lZPos < lMinZ then lMinZ := lZPos;
421
   if lZPos > lMaxZ then lMaxZ := lZPos;
422
   if lZpos > lMinZBound then Check(lVal -lSliceSz);//check previous slice
423
   if lZPos < lMaxZBound then Check(lVal + lSliceSz); //check next slice
424
425
   incQra(lQTail,lQSz); //done with this pixel
426
END;
427
428
procedure FillStart (lPt: integer); {FIFO algorithm: keep memory VERY low}
429
var lI: integer;
430
begin
431
  //1414 follows
432
  for lI := 1 to lQsz do
433
      lQra^[lI] := 0;
434
  lQHead := 0;
435
  lQTail := 1;
436
  Check(lPt);
437
  RetirePixel;
438
  while ((lQHead+1) <> lQTail) do begin//complete until all voxels in buffer have been tested
439
        RetirePixel;
440
		if (lQHead = lQSz) and (lQTail = 1) then
441
           exit; //break condition: avoids possible infinite loop where QTail is being incremented but QHead is stuck at maximum value
442
  end;
443
end;
444
445
procedure SelectClusters (lInput,lOutput: integer);
446
begin
447
     lClusterSz := 0;
448
     lClusterInputValue := lInput;
449
     lClusterOutputValue := lOutput;
450
	 FillStart(lOrigin);
451
end;
452
453
function Lo (lVolumeEdge,lObjectEdge: integer): integer;
454
begin
455
    if lVolumeEdge > lObjectEdge then
456
       result := lObjectEdge
457
    else begin
458
        lAtEdge := true;
459
        result := lVolumeEdge;
460
    end;
461
end;
462
463
function Hi (lVolumeEdge,lObjectEdge: integer): integer;
464
begin
465
    if lVolumeEdge < lObjectEdge then
466
       result := lObjectEdge
467
    else begin
468
        lAtEdge := true;
469
        result := lVolumeEdge;
470
    end;
471
end;
472
473
begin
474
	 lXOrigin := lXOriginIn;
475
	 lVolSz := lXdim*lYdim*lZdim;
476
	 if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems <> lVolSz then begin
477
		 showmessage('You need to draw or load a VOI in order to use the 3D bubble tool.');
478
		 exit;
479
	 end;
480
	 CreateUndoVol;
481
     lSliceSz := lXdim * lYdim;
482
     lMinX:=lXOrigin;
483
     lMaxX:=lXOrigin;
484
     lMinY:=lYOrigin;
485
     lMaxY:=lYOrigin;
486
     lMinZ:=lZOrigin;
487
     lMaxZ:=lZOrigin;
488
   lMinXBound := 1;
489
   lMaxXBound := lXDim;
490
   lMinYBound := 1;
491
   lMaxYBound := lYDim;
492
   lMinZBound := 1;
493
   lMaxZBound := lZDim;
494
     lOrigin := lXOrigin + ((lYOrigin-1)*lXdim)+((lZOrigin-1)*lSliceSz);
495
	 if (lOrigin > lVolSz) or (lXDim < 4) or (lYDim < 4) or (lZDim < 4) or (lVolSz < 1) {or (gROIBupSz <> lVolSz )} then exit;
496
	 if (gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lOrigin] = 0) then begin
497
        showmessage('You must click directly on a ROI to select it. The 3D ROI bubble tool will not work unless you choose the ROI you wish to fill/delete.');
498
        exit;
499
	 end;
500
     GetMem(lROIBuf, lVolSz);
501
	 for lInc := 1 to lVolSz do
502
		 if gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lInc] > 0 then//ROI
503
            lROIBuf^[lInc] := 1
504
         else
505
             lROIBuf^[lInc] := 0;
506
     //BEGIN: define selected ROI contiguous cluster
507
     lQSz := (lVolSz div 4)+8;
508
     GetMem(lQra,lQsz * sizeof(longint) );
509
     lVariability := 0; //only convert images that are exactly 1
510
     SelectClusters(1,255); //selected 3D ROI is 255, other ROI = 1, nonROI 0
511
     //END: define selected roi
512
     //BEGIN: either delete selected ROI, _OR_ fill bubbles in selected ROI
513
     if lDeleteNotFill then begin
514
	   for lInc := 1 to lVolSz do
515
		 if lROIBuf^[lInc] = 1 then    //alfa
516
			lROIBuf^[lInc] := gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lInc] //a different ROI
517
		 else
518
			lROIBuf^[lInc] := 0;//gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer[lInc]; //1402 selected ROI or non-ROI
519
	 end else begin //fill bubbles in selected ROI
520
		 //FindROIbounds;
521
   lMinXBound := Hi(1,lMinX-1);
522
   lMaxXBound := Lo(lXDim,lMaxX+1);
523
   lMinYBound := Hi(1,lMinY-1);
524
   lMaxYBound := Lo(lYDim,lMaxY+1);
525
   lMinZBound := Hi(1,lMinZ-1);
526
   lMaxZBound := Lo(lZDim,lMaxZ+1);
527
	 lOrigin := (lMinXBound) + ((lMinYBound-1)*lXdim)+((lMinZBound-1)*lSliceSz);
528
          lVariability := 2;//convert voxels that are either 0 or 1 to 1
529
          SelectClusters(1,128);
530
          //now bubbles trapped in volume are set to zero
531
          //we next need to distinguish bubbles from unmarked voxels outside the searched object boundary
532
          for lZInc := lMinZBound to lMaxZBound do begin
533
              lSlicePos := (lZInc-1) * lSliceSz;
534
              for lYInc := lMinYBound to lMaxYBound do begin
535
                  lYPos := (lYInc-1) * lXDim;
536
                  for lXInc := lMinXBound to lMaxXBound do begin
537
                      lInc :=  lXInc + lYPos + lSlicePos;
538
                      if lROIBuf^[lInc] = 0 then lROIBuf^[lInc] := 33;
539
                  end; //for X
540
			  end; //for Y
541
          end; //for Z
542
543
          for lInc := 1 to lVolSz do
544
			  if lROIBuf^[lInc] = 33 then
545
				lROIBuf^[lInc] := kVOI8bit //bubble in selected ROI
546
			  else
547
				lROIBuf^[lInc] := gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lInc];
548
	 end;
549
     Freemem(lQra);
550
     //BEGIN: CREATE 3D UNDO BUFFER
551
	 (*if (gDynSz > 1) and (gDynSz = gImageBackupSz) then begin
552
        if (gUndoBufSz > 0) then freemem(gUndoBuffer);
553
        gUndoBufSz := gDynSz;
554
        getmem(gUndoBuffer,gDynSz);
555
        Move(gImageBackupBuffer^,gUndoBuffer^,gImageBackupSz);
556
        gSaveUndoBuf := true;
557
	 end;   (**)
558
     //END: CREATE 3D UNDO BUFFER
559
     //BEGIN: mopping up: prepare data for viewing, report ROI change
560
	 Move(lROIBuf^,gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^,lVolSz);
561
	 Freemem(lROIBuf);  {}
562
	gBGImg.VOIchanged := true;
563
	 //END: mopping up
564
	ImgForm.RefreshImagesTimer.enabled := true;
565
end;  (**)
566
567
procedure TAutoROIForm.AutoROIBtnClick(Sender: TObject);
568
begin
569
	AutoROIForm.ModalResult := mrOK;
570
	AutoROIForm.close;
571
end;
572
573
procedure TAutoROIForm.CancelBtnClick(Sender: TObject);
574
begin
575
	 AutoROIForm.close;
576
end;
577
578
procedure TAutoROIForm.AutoROIchange(Sender: TObject);
579
begin
580
     if not AutoROIForm.visible then exit;
581
     Timer1.Enabled := true;
582
end;
583
584
procedure TAutoROIForm.Timer1Timer(Sender: TObject);
585
begin
586
Timer1.Enabled := false;
587
PreviewBtnClick(sender);
588
end;
589
590
procedure TAutoROIForm.FormDestroy(Sender: TObject);
591
begin
592
	 //if gImageBackupSz <> 0 then Freemem(gImageBackupBuffer);
593
     //gImageBackupSz := 0;
594
end;
595
596
  {$IFDEF FPC}
597
initialization
598
  {$I autoroi.lrs}
599
{$ENDIF}
600
601
end.