8
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
9
ExtCtrls, Buttons, Spin,Process,nifti_img,define_types,CropEdges, userdir;
13
TBETForm = class(TForm)
15
SmoothnessEdit: TFloatSpinEdit;
18
AboutBtn: TSpeedButton;
19
CropBtn: TSpeedButton;
20
procedure CropBtnClick(Sender: TObject);
21
procedure GoBtnClick(Sender: TObject);
22
procedure SpeedButton2Click(Sender: TObject);
24
{ private declarations }
26
{ public declarations }
37
procedure TBETForm.SpeedButton2Click(Sender: TObject);
39
Showmessage('You can skull strip scans to allow you to render the surface of the brain.'+chr (13)
40
+ 'This uses Steve Smith''s Brain Extraction Tool [BET].'+chr (13)+
41
'Default smoothness is 0.50, smaller values generate larger estimates of brain size.'+chr (13)
42
+'http://www.fmrib.ox.ac.uk/fsl');
45
//lCmd := extractfilepath(paramstr(0))+'bet "'+lSourceFilename+'" "'+SaveDialog1.Filename
46
// +'" -f '+floattostr(SmoothnessEdit.value{/100});
47
function PathExists (lCmd: string): boolean;
50
if FSize(lCmd) < 1 then begin
51
BETForm.Memo1.Lines.Add('Unable to find executable named '+lCmd);
57
procedure RunCmd (lCmd: string);
60
AStringList: TStringList;
62
AProcess := TProcess.Create(nil);
63
AStringList := TStringList.Create;
64
AProcess.CommandLine := lCmd;
66
AProcess.Environment.Add(gBGImg.FSLDIR);
67
AProcess.Environment.Add(gBGImg.FSLOUTPUTTYPE);
69
//AProcess.Environment.Add('FSLDIR=/usr/local/fsl');
70
//AProcess.Environment.Add('FSLOUTPUTTYPE=NIFTI_GZ');
72
AProcess.Options := AProcess.Options + [poWaitOnExit, poStderrToOutPut, poUsePipes];
74
AStringList.LoadFromStream(AProcess.Output);
75
BetForm.Memo1.Lines.AddStrings(AStringList);
81
function DoBET(lInFile,lOutFile: string; lFrac: single):boolean;
87
lCmd := extractfilepath(paramstr(0))+'bet';
91
if not PathExists (lCmd) then begin
92
lCmd := '/usr/local/fsl/bin/bet_8UI';
93
if not PathExists (lCmd) then begin
94
lCmd := '/usr/local/fsl/bin/bet';
95
if not PathExists (lCmd) then
98
end; //no bet in home folder...
99
lCmd := lCmd+' "'+lInFile+'" "'+lOutFile +'" -f '+floattostr(lFrac);
100
BETForm.Memo1.Lines.Add(lCmd);
102
(*AProcess := TProcess.Create(nil);
104
AProcess.Environment.Add('FSLDIR=/usr/local/fsl');
105
AProcess.Environment.Add('FSLOUTPUTTYPE=NIFTI_GZ');
107
AProcess.CommandLine := lCmd;
108
//AProcess.CommandLine := 'C:\bet "C:\txx.hdr" "C:\btxx.hdr" -f 0.5';
109
AProcess.Options := AProcess.Options + [poWaitOnExit];
115
function Bright95Pct: byte;//returns intensity of 95th percentile
117
lPos,l5Pct,lCumulative: integer;
118
lHisto: array [0..255] of integer;
121
if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<1) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<>gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems) then exit;
122
//next - create histogram of intensity
123
for lPos := 0 to 255 do
125
for lPos := 1 to gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems do
126
inc(lHisto[gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lPos]]);
127
//next find 95th percentile
128
l5Pct := (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems div 20);
131
while (lPos > 0) and (lCumulative < l5Pct) do begin
133
lCumulative := lCumulative + lHisto[lPos];
138
procedure CropVOI (lVOIIntensity: byte);
142
if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<1) or (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems<>gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems) then exit;
143
for lPos := 1 to gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems do
144
if gMRIcroOverlay[kVOIOverlayNum].ScrnBuffer^[lPos] = kVOI8bit then
145
gMRIcroOverlay[kBGOverlayNum].ScrnBuffer^[lPos] := lVOIIntensity;
148
procedure DeleteHdrImg(lFilename: string);
151
if lFilename = '' then
153
DeleteFile(lFilename);
154
if (UpCaseExt(lFileName)='.IMG') then
155
DeleteFile(changefileext(lFilename,'.hdr'));
156
if (UpCaseExt(lFileName)='.HDR') then
157
DeleteFile(changefileext(lFilename,'.img'));
160
function Mask8BitImg(lImgName,lMaskName: string): boolean;
161
//should be two 8-bit image files of identical dimensions
162
//all non-zero voxels in the mask are written with value of img
163
//Warning - only works with .img files with zero voxoffset - can corrupt .nii files - would need to read header....
165
lPos2,lPos,lC,lSz,lMaskSz,lBPP: integer;
170
lSz := FSize(lImgName);
171
lMaskSz := FSize(lMaskName);
172
if lSz = lMaskSz then
174
else if lSz = (2*lMaskSz) then
176
else if lSz = (2*lMaskSz) then
180
if (lSz < 1) or (lBPP = 0 ) then
184
AssignFile(lInF, lMaskName);
186
BlockRead(lInF, lMask^, lMaskSz);
190
AssignFile(lInF, lImgName);
192
BlockRead(lInF, lImg^, lSz);
195
for lPos := 1 to lMaskSz do
196
if lMask^[lPos] = 0 then begin
197
lPos2 := ((lPos-1)*lBPP);
198
for lC := 1 to lBPP do
199
lImg^[lC+lPos2] := 0;
202
//next save masked image
203
AssignFile(lInF, lImgName); //1/2008....
204
//AssignFile(lInF, lMaskName);
206
BlockWrite(lInF, lImg^, lSz);
212
(*function Mask8BitImg(lImgName,lMaskName: string): boolean;//should be two 8-bit image files of identical dimensions
213
//all non-zero voxels in the mask are written with value of img
214
//Note: the mask file is changed - not the image
220
//showmessage( lMaskName+'xx'+lImgName);
222
lSz := FSize(lImgName);
223
if (lSz < 1) or (lSz <> FSize(lMaskName)) then
228
AssignFile(lInF, lMaskName);
230
BlockRead(lInF, lMask^, lSz);
234
AssignFile(lInF, lImgName);
236
BlockRead(lInF, lImg^, lSz);
239
for lPos := 1 to lSz do
240
if lMask^[lPos] = 0 then
243
//next save masked image
244
AssignFile(lInF, lMaskName);
246
BlockWrite(lInF, lImg^, lSz);
252
function DefaultsDirCmd: string;
253
//Lazarus for Unix does not seem to execute TProcess commands to ~/.. we need to write them to /Home/chris/..
259
lStr := extractfiledir(GetAppConfigFile(false));
260
lLen := length(lStr);
261
if lLen < 1 then exit;
263
while (lP > 0) and (lStr[lP] <> '.') do
266
for lLen := 1 to (lP-1) do
267
result := result + lStr[lLen];
269
{$ELSE} //else ... assume windows
270
result := DefaultsDir('')
272
//showmessage('x'+result+'x');
275
procedure TBETForm.GoBtnClick(Sender: TObject);
279
lTempNameOrig,lTempName8bitMask,lTempBetName,lTempGZName: string;
282
Memo1.lines.add('Startup Timestamp: '+DateTimeToStr(Now));
283
if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) then begin
284
showmessage('BET error: please use File/Open to display the image you want to brain extract.');
286
//showmessage(DefaultsDirCmd);
287
lTempNameOrig :=DefaultsDirCmd+'orig.hdr';//lTempNameOrig := extractfilepath(paramstr(0))+'orig.hdr';
288
SaveAsVOIorNIFTIcore (lTempNameOrig, gMRIcroOverlay[kBGOverlayNum].ImgBuffer,gMRIcroOverlay[kBGOverlayNum].ImgBufferItems, gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr);
289
//SaveAsVOIorNIFTIcore (lTempNameOrig, gMRIcroOverlay[kBGOverlayNum].ImgBuffer,gMRIcroOverlay[kBGOverlayNum].ImgBufferItems, gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP,gMRIcroOverlay[kBGOverlayNum].NiftiHdr);
290
if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 0 then begin
291
case MessageDlg('Do you wish to protect tissue shown by the VOI drawing?', mtConfirmation, [mbYes, mbNo], 0) of
292
mrYes: CropVOI(Bright95Pct);
293
end; //case for protecting VOI
294
ImgForm.CloseVOIClick(nil);
296
if gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP <> 1 then
297
Memo1.lines.add('Warning: converted image downsampled to 8-bit precision.');
298
lTempName8bitMask := DefaultsDirCmd+'temp8.hdr';//lTempName8bitMask := extractfilepath(paramstr(0))+'temp8.hdr';
299
SaveAsVOIorNIFTIcore (lTempName8bitMask, gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr);
300
lTempName8bitMask := changefileext(lTempName8bitMask,'.hdr'); //SaveAs renames the .hdr to .img
301
lTempBetName := DefaultsDirCmd+'btemp8.hdr';//lTempBetName := extractfilepath(paramstr(0))+'btemp8.hdr';
302
// showmessage(lTempBetName);
303
if not DoBET(lTempName8bitMask,lTempBetName,SmoothnessEdit.value) then goto 666;
304
Memo1.lines.add('Shutdown Timestamp: '+DateTimeToStr(Now));
305
if Fileexists(lTempBetName) then begin
306
CopyFileEXoverwrite(lTempName8bitMask,lTempBetName); //the old version of BET corrupts some NIfTI information
308
//assume new version of bet_8UI has saved as .nii.gz
309
lTempGZName := ChangeFileExt(lTempBetName,'.nii.gz');
310
if not Fileexists(lTempGZName) then begin
311
Memo1.lines.add('BET Error: unable to find BET image '+lTempBetName+ ' or '+lTempGZName);
313
Memo1.lines.add(' Try relaunching MRIcron from the Terminal command line, e.g. /Applications/mricron.app/mricron &');
315
//Memo1.Lines.SaveToFile('/Users/crlab/junk.txt');
318
//convert .nii.gz to hdr/.img so we can mask it...
319
ImgForm.CloseImagesClick(nil);
320
ImgForm.OpenAndDisplayImg(lTempGZName,True);
321
SaveAsVOIorNIFTIcore (lTempBetName,gMRIcroOverlay[kBGOverlayNum].ScrnBuffer, gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr);
322
//SaveAsVOIorNIFTIcore (lTempBetName, gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr);
324
DeleteHdrImg(lTempGZName);
325
ImgForm.CloseImagesClick(nil);
327
Mask8BitImg(changefileext(lTempNameOrig,'.img'),changefileext(lTempBetName,'.img'));
328
//ImgForm.OpenAndDisplayImg(lTempBetName,True); // 1/2008
329
ImgForm.OpenAndDisplayImg(lTempNameOrig,True);
330
Memo1.lines.add('Use File/SaveAsNIfTI to save the stripped 8-bit image.');
333
DeleteHdrImg(lTempBetName);
334
DeleteHdrImg(lTempNameOrig);
335
DeleteHdrImg(lTempName8bitMask);
338
procedure TBETForm.CropBtnClick(Sender: TObject);
344
lTempNameOrig,lTempName8bitMask,lTempBetName: string;
347
Memo1.lines.add('Startup Timestamp: '+DateTimeToStr(Now));
348
if (gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems < 1) then begin
349
showmessage('BET error: please use File/Open to display the image you want to brain extract.');
352
if gMRIcroOverlay[kVOIOverlayNum].ScrnBufferItems > 0 then begin
353
case MessageDlg('Do you wish to remove tissue shown by the VOI drawing?', mtConfirmation,
356
else case MessageDlg('Do you wish to protect tissue shown by the VOI drawing?', mtConfirmation,
359
lTempNameOrig := DefaultsDir('')+'orig8.hdr';
360
SaveAsVOIorNIFTIcore (lTempNameOrig, gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr);
361
CropVOI(Bright95Pct);
364
end; //case for protecting VOI
365
end; //case for deleting VOI
367
ImgForm.CloseVOIClick(nil);
369
if gMRIcroOverlay[kBGOverlayNum].ImgBufferBPP <> 1 then
370
Memo1.lines.add('Warning: converted image downsampled to 8-bit precision.');
371
lTempName8bitMask := DefaultsDir('')+'temp8.hdr';
372
SaveAsVOIorNIFTIcore (lTempName8bitMask, gMRIcroOverlay[kBGOverlayNum].ScrnBuffer,gMRIcroOverlay[kBGOverlayNum].ScrnBufferItems, 1,gMRIcroOverlay[kBGOverlayNum].NiftiHdr);
373
lTempName8bitMask := changefileext(lTempName8bitMask,'.hdr'); //SaveAs renames the .hdr to .img
374
lTempBetName := DefaultsDir('')+'btemp8.hdr';
375
DoBET(lTempName8bitMask,lTempBetName,SmoothnessEdit.value);
376
Memo1.lines.add('Shutdown Timestamp: '+DateTimeToStr(Now));
378
CopyFileEXoverwrite(lTempName8bitMask,lTempBetName); //the old version of BET corrupts some NIfTI information
379
DeleteHdrImg(lTempName8bitMask);
380
if lTempNameOrig <> '' then begin
381
Mask8BitImg(changefileext(lTempNameOrig,'.img'),changefileext(lTempBetName,'.img'));
382
DeleteHdrImg(lTempNameOrig);
384
ImgForm.OpenAndDisplayImg(lTempBetName,True);
385
Memo1.lines.add('Use File/SaveAsNIfTI to save the stripped 8-bit image.');
386
DeleteHdrImg(lTempBetName);
388
(*procedure TBETForm.GoBtnClick(Sender: TObject);
391
Memo1.lines.add('Startup Timestamp: '+DateTimeToStr(Now));
392
DoBET('C:\txx.hdr','C:\btxx.hdr',SmoothnessEdit.value);
393
Memo1.lines.add('Shutdown Timestamp: '+DateTimeToStr(Now));