その漫画自炊オタクはImageJマクロに恋をする

プログラミングを用いた、自炊漫画の画像処理

【上級者向け】寝てる間に自動解析してコントラスト調整やリサイズ処理などなどするMacro

 

f:id:yu3xx:20210627093020p:plain


  

最初から最後まで全く手を触れずに、コントラスト濃度変更処理などを実行することができるマクロです。

 

 

もくじ

 

 

コード

//PreInput Almighty.ijm
//based Almighty ver3.3.0
//ContrastAdjust (As necessary, for 8bit, FullColor)
//Optimize minAndMax (As necessary, Manual 3trials)
//Optimize minAndMaxAuto (As necessary)
//SetResolution (As necessary, for any Type)
//NombreCut type1 (As necessary, UseOneROI)
//NombreCut type2 (As necessary, CaseDivided by ODD/EVEN, [number==0 -> error])
//Renumbering from1 (As necessary, Files must be in subDirectory)
//Renumbering ATMT (As necessary, Automater, Only one trueTitle, trueTitle=pureTitle+kansuu) 
//MakeDirAuto (FileName : trueTitle_pagenumber.ext)
//output txtFile (optMinMaxAuto)

//opDir no hitotsu sita no kaisou no directories ni SOREZORE "Almighty" wo kakeru


version = "4.1.0";

//1.2.0 -> hosei2
//1.3.0 -> enter cFiles
//2.0.0 -> Forced to proceed even if files are not in the subDirectory
//2.2.0 -> targetMeanBlack = 13 (optMinAndMaxAuto)
//3.0.0 -> pageCount
//3,1,0 -> pageCount%mabiki == 0
//3.2.0 -> xStep = 3*xSeg
//3.3.0 -> Sharpen
//3.4.0 -> }else if(procCount < cFiles){ ..... listFiles2
//3.5.0 -> run("Input/Output...", "jpeg=quality gif=-1 file=.csv copy_column copy_row save_column save_row");
//4.0.0 -> flagExtactRedChannel
//4.1.0 -> resize org.jpg (optMinMaxAuto)


print("");
print("Pre Input");
print("Almighty Processing");
print("ver",version);
print("makeDirAuto");
print("listFilesRecursively");

print("");
print("Subfolder Goto ni optMinMaxAuto");
print("Full Auto");
print("");

startTime = whatTimeNow();



//Select opDir
opDir=getDirectory("choose a directory");
listOp = getFileList(opDir);
print("opDir :",opDir);











//------------------------------------------

//Select Processing (enter 0 or 1)
flagContr = 1;
flagReso = 1;
flagNombre = 0;
flagSharpen = 1;
flagOptMinMaxAuto = 1;
flagOptMinMax = 0; 
flagExtactRedChannel = 0;
flagRenumFrom1 = 0;
flagRenumATMT = 0;


//------------------------------------------

//------------------------------------------

//Enter Parameter
min = 0;
max =255;
flagFullColor = 0;
preDpi = 300;
postDpi = 400;
digit = 4;
output = "JPEG";

cFiles = 11;

hosei = -10;	//adjust Max
hosei2 = 0;	//adjust min, default=5 (targetMeanBlack=27), 

//------------------------------------------











//Define variable
flagFullColor = 0;
var flagExtactRedChannel;
flagSave = 1;
flagOpenDir = 0;
var totalFiles = 0;
var procCount = 0;

var min;
var max;
var digit;
var compressionRate;
var ext;
var optimizedMin;
var optimizedMax;
var targetMeanWhite;
var targetMeanBlack;
var sumMin;
var sumMax;
var mabiki;
var OPT_MAX;  
var OPT_MIN;
var cFiles;
var aCountMin;
var aCountMax;
var f;
var name;
var pageCount;

if(flagSave == 1){
	saveDir = getDirectory("downloads");
	print("Save to :",saveDir);
	selectWindow("Log");
}
wait(1000);

//make parentDirectory
timeStamp = getTimeStamp();
parentDir = saveDir+"postProc_"+timeStamp+"/";
File.makeDirectory(parentDir);


//output txt (optMinMaxAuto)
if(flagOptMinMaxAuto == 1) {
	outputTxt = saveDir + "postProc_"+timeStamp+".txt";
	 f = File.open(outputTxt);
}


//Loop START!!
for(m=0; m<listOp.length; m++){
	openDir=opDir+listOp[m];
	if(!endsWith(listOp[m],"/")) {
		showMessageWithCancel("Found files that are NOT in the subDirectory. Check opDir. Do you wanna continue?");
		openDir = opDir;
		m = listOp.length + 1;//break after this loop
	}
	print("openDir:", openDir);
	opeLoop();
}


//fin

finishTime = whatTimeNow();
print("Start Time .... ",startTime);
print("FinishTime ... ",finishTime);
print("oshimai");
beep();




//-----------------------------------------------------------------------------
//Define opeLoop

function opeLoop(){
totalFiles = 0;
procCount = 0;

//print flag
print("");
if(flagContr == 1) print("flagContr = ON");
if(flagReso == 1) print("flagReso = ON");
if(flagNombre == 1) print("flagNombre = ON");
if(flagSharpen == 1) print("flagSharpen = ON");
if(flagOptMinMax == 1) print("flagOptMinMax = ON");
if(flagOptMinMaxAuto == 1) print("flagOptMinMaxAuto = ON");
if(flagExtactRedChannel == 1) print("flagExtactRedChannel = ON");
if(flagRenumFrom1 == 1) print("flagRenumFrom1 = ON");
if(flagRenumATMT == 1) print("flagRenumATMT = ON");

//check flag
print("");
if(flagRenumFrom1 == 1 && flagRenumATMT == 1) exit("Two \"Renumbering Processing\" were selected.");
if(flagOptMinMax == 1 && flagOptMinMaxAuto == 1) exit("Two \"OptMinMax Processing\" were selected.");
if(flagFullColor == 1 && flagExtactRedChannel == 1) exit("flagFullColor and flagExtactRedChannel can't be used together");
if(flagOptMinMax == 1 || flagOptMinMaxAuto == 1){
	if(flagContr == 0) print("Only optMinMax processing");
}
if(flagContr == 0 && flagReso == 0 && flagNombre == 0){
	if(flagRenumFrom1 == 1 || flagRenumATMT == 1) print("Only Renumbering processing");
}
if(flagOptMinMax == 1 || flagOptMinMaxAuto == 1){
	if(flagContr == 0 && flagReso == 0 && flagNombre == 0 && flagRenumFrom1 == 0 && flagRenumATMT == 0) {
		flagSave = 0;
		print("flagSave = OFF");
	}
}
if(flagContr == 1 || flagReso == 1 || flagNombre == 1 || flagRenumFrom1 == 1 || flagRenumATMT == 1 || flagOptMinMaxAuto == 1){
	flagOpenDir = 1;
}else{
	print("flagOpenDir = OFF");
}


//Do something for selected folder
print("");
if(flagOpenDir == 1){
	
	print("Processing :",openDir);
	list = getFileList(openDir);
	//count totalFiles
	countFiles(openDir);
	selectWindow("Log");
}


//Select Nombre Type
if(flagNombre == 1){
	Dialog.create("Nombre Cut setting");
	items = newArray("Use One ROI", "Case Divided by ODD/EVEN");
	Dialog.addRadioButtonGroup("Select NombreCut Type", items, 2, 1, "Use One ROI");
	Dialog.show;
	nombreRadio = Dialog.getRadioButton();
	if(nombreRadio == "Use One ROI") NombreType = 1;
	if(nombreRadio== "Case Divided by ODD/EVEN") NombreType = 2;
}


//Clear ROI Manager and set ROI
if(flagNombre == 1){
	roiCount = roiManager("count");
	if(roiCount > 0){
		roiManager("Deselect");
		roiManager("Delete");
	}
	if(NombreType == 1){
		//ROI setting
		waitForUser("ROI setting","Open an image and set [ROI] using rectangle tool, then click [OK].");
		roiManager("Add");
		close();
	}
	if(NombreType == 2){
		//ROI setting ODD(1,3,5,7,...)
		waitForUser("ODD(1,3,5,7,...)","Open an [ODD number] file and set [ROI] using rectangle tool, then click [OK].");
		roiManager("Add");
		close();

		//ROI setting EVEN(2,4,6,8,...)
		waitForUser("EVEN(2,4,6,8,...)","Open an [EVEN number] file and set [ROI] using rectangle tool, then click [OK].");
		roiManager("Add");
		close();
	}
}


//Enter parameter
if(flagSave == 1){

	//print parameter
	print("");
	if(flagFullColor == 1) print("flagFullColor = ON");
	if(flagOptMinMax == 0 && flagOptMinMaxAuto == 0){
		if (flagContr == 1) print("min =",min,", Max =",max);
	}
	if (flagReso == 1) print("pre dpi =",preDpi,", Target dpi =",postDpi);

	//Extension
	if(output == "JPEG") ext = ".jpg";
	if(output == "PNG") ext = ".png";

	//JPEG,PNG quality setting(jpeg=90,gif=-1)
	quality = 90;
	run("Input/Output...", "jpeg=quality gif=-1 file=.csv copy_column copy_row save_column save_row");
	if (output == "JPEG") print("JPEG quality =",quality);
	print("");
}

//SetResolution Setting
if(flagReso == 1) compressionRate = postDpi/preDpi;


//Reference setting
var referLength;
if(flagRenumATMT == 1){
	referenceCheck(openDir);
}









//optimizeMinAndMax

if(flagOptMinMax == 1) {
	sumMin = 0;
	sumMax = 0;

	trials = 3;
	OPT_MAX = newArray(trials);
	OPT_MIN = newArray(trials);
	for(now=0; now<trials; now++){
		optMinMax(now,trials);
		sumMin = sumMin + OPT_MIN[now];
		sumMax = sumMax + OPT_MAX[now];
	}
	min = floor(sumMin/trials);
	max = floor(sumMax/trials);
	print("");
	wait(1000);

	for(i=0; i<trials; i++){
		print(i+1,"...","min = ",OPT_MIN[i],", max = ",OPT_MAX[i]);
	}
	print("");
	beep();
	wait(1000);

	print("Result...","optMin =",min,", optMax =",max);
	wait(3000);
}

if(flagOptMinMaxAuto == 1) {
	//Enter parameter
	
	targetMeanWhite = 254.97;
	targetMeanBlack = 13;
	print("targetMeanWhite =",targetMeanWhite );
	print("targetMeanBlack =",targetMeanBlack );
	//mabiki = 60;

	//Do something for selected folder
	tempDir = saveDir + "Temp_optMinMax/";
	print("Temp dir :",tempDir);
	selectWindow("Log");
	wait(1000);

	//make tempDir
	if(!File.exists(tempDir)){
		File.makeDirectory(tempDir);
	}
	
	//Create Array
	//cFiles = floor(totalFiles/mabiki);
	
	cFiles = floor(cFiles);
	mabiki = floor(totalFiles/cFiles);
	if(mabiki < 1) exit("Error! Mottto cFiles Sukunaku.");
	print("cFiles =",cFiles,", mabiki =",mabiki);	

	OPT_MAX = newArray(cFiles);
	OPT_MIN = newArray(cFiles);

	for(i=0; i<cFiles; i++){
		OPT_MAX[i] = 0;
	}
	for(i=0; i<cFiles; i++){
		OPT_MIN[i] = 255;
	}
	
	procCount = 0;
	setBatchMode(true);
	pageCount = 0;
	listFiles2(openDir);
	setBatchMode(false);

	optMinMaxResults();
	min = optimizedMin;
	max = optimizedMax;
	
	print("");
	wait(1000);

	print("acceptCount...min : ",aCountMin,", max : ",aCountMax);
	beep();
	wait(1000);
	
	print("Result...","optMin =",min,", optMax =",max);
	wait(3000);
}

//exit (only optMinMax)
if(flagSave == 0){
	exit("oshimai");
}



//Renum from1
if (flagRenumFrom1 == 1){
	Table.create("Correspondence Table");
}


//Main Operation
print("Now Operation...");
setBatchMode(true);
procCount = 0;
listFiles(openDir);


//clear ROI Manager
if(flagNombre == 1){
	roiManager("Deselect");
	roiManager("Delete");
}


//fin
if (flagRenumFrom1 == 1){
	Table.update;
}

print("");
if(flagOptMinMax == 1){
	for(i=0; i<trials; i++){
		print(i+1,"...","min =",OPT_MIN[i],", max =",OPT_MAX[i]);
	}
}
if(flagOptMinMaxAuto == 1) print("acceptCount...min : ",aCountMin,", max : ",aCountMax);
if(flagOptMinMax == 1 || flagOptMinMaxAuto == 1){
	print("Result...","optMin =",min,", optMax =",max);
	print("");
}
if (flagContr == 1) {
	print("Contrast Adjust by...");
	print("min =",min,", max =",max);
}
if (flagReso == 1) print("Compression Rate =",compressionRate);
if(flagSharpen == 1) print("Sharpen");
if (output == "JPEG") print("JPEG quality =",quality);




}//Fn_opeLoop End


//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define referenceCheck

function referenceCheck(dir){
	list = getFileList(dir);
	if(endsWith(list[0],"/")){
		referenceCheck(dir+list[0]);
	}else{
		name = list[0];
		dotIndex = lastIndexOf(name,".");
		title = substring(name,0,dotIndex);
		space = lastIndexOf(title," ");
		trueTitle = substring(title,0,space);
		number = substring(title,space+1);

		reference = trueTitle;
		referLength = lengthOf(reference);
		selectWindow("Log");
		print("Check trueTitle. (e.g. NARUTO_60)");
		print("trueTitle=[",trueTitle,"]");
		showMessageWithCancel("Check trueTitle (except : number.ext), and click [OK].");
	}
}
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define countFiles

function countFiles(dir){
	list = getFileList(dir);
	for(i=0; i<list.length; i++){
		if(endsWith(list[i],"/")){
			countFiles(dir+list[i]);
		}else{
			totalFiles++;
		}
	}
	
}
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define listFiles

function listFiles(dir){
	list = getFileList(dir);
	for(i=0; i<list.length; i++){
		if(endsWith(list[i],"/")){
			listFiles(dir+list[i]);
		}else{
			open(dir+list[i]);
			operation();
		}
	}
	
}
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define listFiles2

//caution!! For optMinMaxAuto

function listFiles2(dir){
	list = getFileList(dir);
	for(i=0; i<list.length; i++){
		if(endsWith(list[i],"/")){
			listFiles2(dir+list[i]);
		}else if(procCount < cFiles){
			pageCount++;
			if(pageCount % mabiki == 0){
				open(dir+list[i]);
				optMinMaxAuto();
			}
		}
	}
	
}
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define Main operation

function operation(){
	

	procCount++;
	
	//Progress.the second decimal place
	//print(procCount,"/",totalFiles,"...Progress=",d2s(procCount/totalFiles*100,2),"%");
	
	//Rename Section
	if(flagRenumATMT == 1){
		name = getTitle();
		dotIndex = lastIndexOf(name,".");
		title = substring(name,0,dotIndex);

		//ReNumbering
		titleLength = lengthOf(title);

		if(referLength < titleLength){
			space = lastIndexOf(title," ");
			trueTitle = substring(title,0,space);
			number = substring(title,space+1);

			newname = trueTitle+"_"+zeroPad(number,digit)+ext;
		
		}else if(referLength == titleLength){

			newname = title+"_"+zeroPad(1,digit)+ext;

			dotIndex = lastIndexOf(newname,".");
			title = substring(newname,0,dotIndex);
			underBar = lastIndexOf(title,"_");
			trueTitle = substring(title,0,underBar);
			number = substring(title,underBar+1);
		}	
	}else if(flagRenumATMT == 0){
		name = getTitle();
		dotIndex = indexOf(name, ".");
		title = substring(name,0,dotIndex);
		underBar = lastIndexOf(title,"_");
		trueTitle = substring(title,0,underBar);
		number = substring(title,underBar+1);
		newname = title+ext;	
		if (flagRenumFrom1 == 1) newname = trueTitle+"_"+zeroPad(i+1,digit)+ext;
	}
	rename(newname);

	//Output Correspondence table
	if (flagRenumFrom1 == 1){
		Table.set("index",procCount-1,procCount);
		Table.set("Original",procCount-1,name);
		Table.set("Newname",procCount-1,newname);
	}

	//Nombre Cut
	if(flagNombre == 1){
		if(NombreType == 1){
			roiManager("Select", 0);
			run("Crop");
		}
		if(NombreType == 2){
			number = parseInt(number);
			if(number == 0) exit("Error!! Number must not be null.");
			//ODD(1,3,5,7,...)
			if(number%2 == 1){
				roiManager("Select", 0);
				run("Crop");
			}
			//EVEN(2,4,6,8,...)
			if(number%2 == 0){
				roiManager("Select", 1);
				run("Crop");
			}
		}
	}

	//SetResolution
	if (flagReso == 1){
		width = getWidth;
		height = getHeight;
		targetW = floor(width*compressionRate);
		run("Size...", "width=targetW constrain average interpolation=Bicubic");
	}

	//Filtering
	if(flagSharpen == 1){
		run("Sharpen");
		// ---equiv--- //run("Convolve...", "text1=[-1 -1 -1\n-1 12 -1\n-1 -1 -1\n] normalize"); 
	}

	//ContrastAdjust 8 bit
	depth = bitDepth();
	if(flagFullColor == 0) {
		if (depth == 8) {
			//ContrastAdjust (As necessary)
			if (flagContr == 1) setMinAndMax(min, max);
			if (flagContr == 1) run("Apply LUT");
		}
	}
	if(flagFullColor == 1) {
		//ContrastAdjust (As necessary)
		if (flagContr == 1) setMinAndMax(min, max);
		if (flagContr == 1) run("Apply LUT");
	}
	
	if(flagExtactRedChannel == 1) {
		//extract red channel to suppress yellowing
		run("RGB Stack");
		setSlice(1);	//red stack
		//ContrastAdjust
		if (flagContr == 1) setMinAndMax(min, max);
		if (flagContr == 1) run("Apply LUT", "stack");
	}

	

	//Save to SubDirectory
	subDir = parentDir+trueTitle+"/";
	if(!File.exists(subDir)){
		File.makeDirectory(subDir);
	}

	if (flagContr == 0 && flagReso == 0 && flagNombre == 0) {
		if(flagRenumFrom1 == 1 || flagRenumATMT == 1){
			File.copy(dir+name,subDir+newname);
			//print("Copy to...",subDir+newname);
		}
	}else{		
		saveAs(output, subDir+newname);
		//print("Save to...",subDir+newname);
	}
	close(newname);
}
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define optMinMax

function optMinMax(now,trials){

	print("");
	print("OptimizeMinAndMax");
	setBatchMode(false);

	if(nImages == 0) waitForUser("OptMinAndMax.  Open an image, then click [OK]"); 

	//Enter parameter
	if(now == 0){
		Dialog.create("OptMinAndMax Setting");
		Dialog.addNumber("targetMeanWhite",254.97);
		Dialog.addNumber("targetMeanBlack",13); //default->18,27
		Dialog.show;
		targetMeanWhite = Dialog.getNumber();
		targetMeanBlack = Dialog.getNumber();
	}

	if(flagExtactRedChannel == 1) {
		run("RGB Stack");
		setSlice(1);	//red stack
		updateDisplay();
	}

	name = getTitle();
	tempDir = saveDir + "Temp_optMinMax/";
	//make tempDir
	if(!File.exists(tempDir)){
		File.makeDirectory(tempDir);
	}
	saveAs("Jpeg", tempDir+"CheckMaxAndMin.jpg");


	//optimize Max
	setTool("rectangle");
	run("Specify...", "width=100 height=100 x=10 y=10");
	waitForUser("ROI selection","Set ROI on the \"WHITE BACK GROUND\", then click [OK].");
	getStatistics(area,mean);
	setBatchMode(true);

	if(mean < 150){
		exit("Error!! This area is not WHITE BACK GROUND.");
	}
	run("Crop");

	saveAs("Jpeg", tempDir+"CheckMax.jpg");
	close();

	max = 254;
	min = 0;
	print("optimized Max Macro, TargetMean =",targetMeanWhite);

	for (i=0; i<254; i++){
		open(tempDir+"CheckMax.jpg");
		setMinAndMax(min, max);
		run("Apply LUT");
		getStatistics(area,mean);
		print("Max=",max," mean=",mean);
		if(mean >= targetMeanWhite){
			optimizedMax = max;
			i = 255; //break
		}
		max = max-1;
		close();
	}
	print("OptimizedMax =",optimizedMax);
	setBatchMode(false);

	//optimize min
	open(tempDir+"CheckMaxAndMin.jpg");
	setTool("rectangle");
	run("Specify...", "width=100 height=100 x=10 y=10");
	waitForUser("ROI selection","Set ROI on the \"BLACK ZONE\", then click [OK].");
	getStatistics(area,mean);
	setBatchMode(true);

	if(mean > 100){
		exit("Error!! This area is not BLACK ZONE.");
	}
	run("Crop");

	saveAs("Jpeg", tempDir+"CheckMin.jpg");
	close();

	max = optimizedMax;
	min = 1;
	print("");
	print("OptimizedMin Macro, TargetMean=",targetMeanBlack);

	for (i=0; i<254; i++){
		open(tempDir+"CheckMin.jpg");
		setMinAndMax(min, max);
		run("Apply LUT");
		getStatistics(area,mean);
		print("min=",min," mean=",mean);
		if(mean <= targetMeanBlack){
			optimizedMin = min;
			i=255; //break
		}
		min = min+1;
		close();
	}
	
	//Results
	OPT_MIN[now] = optimizedMin;
	OPT_MAX[now] = optimizedMax;
	
	print("");
	print(now+1,"/",trials);
	print("Title =",name);
	print("OptimizedMin =",optimizedMin);
	print("OptimizedMax =",optimizedMax);
	setBatchMode(false);
} 

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define optMinMaxAuto

function optMinMaxAuto(){

	name = getTitle();

	//Progress
	print("");
	print(procCount+1, "/", cFiles, "...Progress=",d2s(procCount/cFiles*100,2),"%" , " [OptMinMaxAuto]");
	print("pageCount = ", pageCount);
	print("...",name);

	if(flagExtactRedChannel == 1) {
		run("RGB Stack");
		setSlice(1);	//red stack
		updateDisplay();
	}

	depth = bitDepth();
	if (depth == 8) {
		run("Size...", "width=400 depth=1 constrain average interpolation=Bilinear");
		saveAs("Jpeg", tempDir+"org.jpg");
		
		width = getWidth();
		height = getHeight();

		x = 0;
		y = 0;

		sum = 0;
		whiteCheckCount = 0;
		blackCheckCount = 0;

		whiteSegCount = 0;
		blackSegCount = 0;

		whiteMax = 0;
		blackMin = 255;

		//whiteBackGround
		segCount = 0;
		xSeg = 10;
		ySeg = 10;
		xStep = xSeg;
		yStep = ySeg;

		for(x=0; x<width-xSeg; x=x+xStep){
			for(xi=0; xi<xSeg; xi++){
				for(yi=0; yi<ySeg; yi++){
					pixelValue = getPixel(x+xi,y+yi);
					sum = sum+pixelValue;
				}
			}
			mean = sum/xSeg/ySeg;
			if(mean > whiteMax) {
				whiteMax = mean;
				whiteSegCount = segCount;
				whiteCheckCount++;
				//print("ImgNo.",procCount+1, ", white-",whiteCheckCount);
				
			}
			makeRectangle(x, y, xSeg, ySeg);
			run("Crop");
			saveTitle = "wSegNo"+zeroPad(segCount,6);
			saveAs("Jpeg", tempDir+saveTitle+".jpg");

			close();
			open(tempDir+"org.jpg");


			sum = 0;
			segCount++;
		}

		//blackKuroBeta
		segCount = 0;
		xSeg = 8;
		ySeg = 8;
		xStep = 2*xSeg;
		yStep = 2*ySeg;

		for(y=0; y<height-ySeg; y=y+yStep){
			for(x=0; x<width-xSeg; x=x+xStep){
				for(xi=0; xi<xSeg; xi++){
					for(yi=0; yi<ySeg; yi++){
						pixelValue = getPixel(x+xi,y+yi);
						sum = sum+pixelValue;
					}
				}
				mean = sum/xSeg/ySeg;
			
				if(mean < blackMin){
					blackMin = mean;
					blackSegCount = segCount;
					blackCheckCount++;
					//print("ImgNo.",procCount+1, ", black-",blackCheckCount);
				}
				makeRectangle(x, y, xSeg, ySeg);
				run("Crop");
				saveTitle = "bSegNo"+zeroPad(segCount,6);
				saveAs("Jpeg", tempDir+saveTitle+".jpg");
	
				close();
				open(tempDir+"org.jpg");

	
				sum = 0;
				segCount++;
			}
		}
		close("org.jpg"); //originalImage
				
		//checkMax Loop
		
		optimizedMax = 0; //If not found
		max = 254;
		min = 0;
	
		print("Checking Max..." , "wSegNo" + zeroPad(whiteSegCount,6) + ".jpg");

		for (i=0; i<254; i++){
			open(tempDir+"wSegNo"+zeroPad(whiteSegCount,6)+".jpg");
			setMinAndMax(min, max);
			run("Apply LUT");
			getStatistics(area,mean);
			if(mean >= targetMeanWhite){
				optimizedMax = max;
				i = 255; //break
			}
			max = max-1;

			//	print(min,max,mean);
			//	print("Checking Max..." , "wSegNo" + zeroPad(whiteSegCount,6) + ".jpg");
			
			close();
		}
		print("Temp_OptimizedMax =",optimizedMax);
		OPT_MAX[procCount] = optimizedMax;
	
		//checkMin Loop

		optimizedMin = 255; //If not found
		max = 220; //Daitai 200 Gurai Ooi kara
		min = 1;
		
		print("Checking Min..." , "bSegNo" + zeroPad(blackSegCount,6) + ".jpg");
	
		for (i=0; i<254; i++){
			open(tempDir+"bSegNo"+zeroPad(blackSegCount,6)+".jpg");
		
			setMinAndMax(min, max);
			run("Apply LUT");
			getStatistics(area,mean);
			if(mean <= targetMeanBlack){
				optimizedMin = min;
				i=255; //break
			}
			min = min+1;

			//	print(min,max,mean);
			//	print("Checking Min..." , "bSegNo" + zeroPad(blackSegCount,6) + ".jpg");
			
			if(min == max){
				i=255; //break
			}

			close();
		}
		print("Temp_OptimizedMin =",optimizedMin);
		OPT_MIN[procCount] = optimizedMin;	

	}else{ //else if(depth != 8bit)
		close(name); //original Image
	}	

	procCount++; //and back to listFiles2
}

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define optMinMaxResults 

function optMinMaxResults(){

	//	//Plot Graphs
	//	i=linspace(1,cFiles,cFiles);
	//	Plot.create("Max","No.","Max",i,OPT_MAX);
	//	Plot.show();
	//	Plot.create("Min","No.","Min",i,OPT_MIN);
	//	Plot.show();
	
	//Max
	aCountMax=0;
	//Outlier Exclusion
	for(i=0; i<cFiles; i++){
		if(OPT_MAX[i] > 150){
			aCountMax++;
		}
	}
	if(aCountMax == 0) exit("Error! Mabiki motto sukunaku.");
	OPT_MAX = bubbleSort(OPT_MAX);
	OPT_MAX = Array.slice(OPT_MAX,cFiles-aCountMax,cFiles);
	
	median = floor(aCountMax/2);
	if(aCountMax % 2 == 0) median = median-1;
	optimizedMax = OPT_MAX[median] + hosei;

	//Min
	aCountMin=0;
	for(i=0; i<cFiles; i++){
		if(OPT_MIN[i] < 100){
			aCountMin++;
		}
	}
	if(aCountMin == 0) exit("Error! Mabiki motto sukunaku.");
	OPT_MIN = bubbleSort(OPT_MIN);
	OPT_MIN = Array.slice(OPT_MIN,0,aCountMin);

	median = floor(aCountMin/2);
	if(aCountMin % 2 == 0) median = median-1;
	optimizedMin = OPT_MIN[median] + hosei2;

	//Results
	print("");
	print("OPT_MIN = ");
	Array.print(OPT_MIN);
	print("OPT_MAX = ");
	Array.print(OPT_MAX);
	print("OptimizedMin =",optimizedMin);
	print("OptimizedMax =",optimizedMax);

	//output txt
	print(f, name + "\t" + "optMin = " + optimizedMin + "\t" + "optMax = " + optimizedMax + "\t" + "acceptCount (min, max) = " + aCountMin + ", " + aCountMax);

}
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define function getTimeStamp

function getTimeStamp(){
	getDateAndTime(year,month,dayOfWeek,dayOfMonth,hour,minute,second,msec);
	timeStamp = "string";
	strYear = ""+year;
	month = month+1;
	if(month < 10){
		strMonth = "0"+month;
	}else{
		strMonth = ""+month;
	}
	if(dayOfMonth < 10){
		strDayOfMonth = "0"+dayOfMonth;
	}else{
		strDayOfMonth = ""+dayOfMonth;
	}
	if(hour < 10){
		strHour = "0"+hour;
	}else{
		strHour = ""+hour;
	}
	if(minute < 10){
		strMinute = "0"+minute;
	}else{
		strMinute = ""+minute;
	}
	if(second < 10){
		strSecond = "0"+second;
	}else{
		strSecond = ""+second;
	}
	timeStamp = strYear+strMonth+strDayOfMonth+"_"+strHour+"h"+strMinute+"m"+strSecond+"s";
	return timeStamp;
}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//Define function whatTimeNow

function whatTimeNow(){
	getDateAndTime(year,month,dayOfWeek,dayOfMonth,hour,minute,second,msec);
	stringTime = "string";
	strYear = ""+year;
	month = month+1;
	if(month < 10){
		strMonth = "0"+month;
	}else{
		strMonth = ""+month;
	}
	if(dayOfMonth < 10){
		strDayOfMonth = "0"+dayOfMonth;
	}else{
		strDayOfMonth = ""+dayOfMonth;
	}
	if(hour < 10){
		strHour = "0"+hour;
	}else{
		strHour = ""+hour;
	}
	if(minute < 10){
		strMinute = "0"+minute;
	}else{
		strMinute = ""+minute;
	}
	if(second < 10){
		strSecond = "0"+second;
	}else{
		strSecond = ""+second;
	}
	stringTime = strYear+"/"+strMonth+"/"+strDayOfMonth+"_"+strHour+":"+strMinute+":"+strSecond;
	return stringTime;
}

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//Define function zeroPadding

function zeroPad(int,digitZeroPad){
	if(int < 0){
		exit("ZeroPadding Error!!  int<0");
	}
	stringInt = ""+int;
	digitStringInt = lengthOf(stringInt);
	digitSubtra = digitZeroPad-digitStringInt;
	if(digitSubtra < 0){
		exit("ZeroPadding Error!!  digitSubtra<0");
	}
	if(digitZeroPad > 0){
		for(i=0; i<digitSubtra; i++){
			stringInt = "0"+stringInt;
		}
	}
	return stringInt;
}	

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define function linspace (generate Arithmetric Sequence)
//a->1st term, an->last term, n->term number

function linspace(a,an,n){
	A = newArray(n);
	d = (an-a)/(n-1);

	for(i=0;i<n;i++){
		A[i] = a+i*d;
	}	

	return A;
}

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
//Define function bubble_sort

function bubbleSort(A){
	n=A.length;
	for(i=0;i<n-1;i++){
		for(j=n-1;j>i;j--){
			if(A[j]<A[j-1]){
				tmp=A[j];
				A[j]=A[j-1];
				A[j-1]=tmp;
			}
		}
	}
	return A;
}

//-----------------------------------------------------------------------------

 

 

ポイント

 

基本的には多目的自炊マクロ「Almighty Processing ver.3」のアレンジ版です。

 

今までと違うのは

① 起動後のダイアログを極力排除して、起動したら終わるまで何もしなくてOK!

 

② 保存先フォルダをPC内の「ダウンロード先フォルダ」に設定したので、いちいち選ばなくてOK!

 

③ 選択した処理フォルダの1つ下の階層のフォルダごとに「Almighty Processing」をかけるイメージなので、コントラスト濃度変更の「Min, Max」が独立別個!

 

④ 解析結果の最適Min Max値をtxtファイルにして書き出し!

 

f:id:yu3xx:20210627094007p:plain

 

プログラムコード内の値を直接いじることで処理内容を決定しているので、ちょっと上級者むけですが、

寝てる間にドカっとまとめて処理したい!

って時におすすめです。

 

 

基本的に、optMinMaxAutoで自動解析した後に、Contrasut Adjustmentでコントラスト・濃度を変更する用に作っています。

なので他の処理を噛ませた時のデバッグはしていないのでご注意を。

 

 

使い分け

 

① 1タイトルだけが対象で、自分の目でカクニンしながら確実に最適なMin, Maxでコントラスト濃度変更したい時

→「Almighty Processing ver.3」で「Optimize MinAndMax (Manual)」

【真・改良版】コントラスト調整やリサイズ処理などなどを、一気にやってしまうためのMacro - その漫画自炊オタクはImageJマクロに恋をする

 

② 複数タイトルが対象で、1タイトルずつMin, Maxを調べるのがメンドウなのでまとめて一気に自動処理させたい時

→本記事の「Pre Input Almighty」で「Optimize MinAndMax (Auto)」

 

 

デフォルトの処理内容

 

0がオフで、1がオンです。このあたりをいじって処理内容を変更してください。

 

 //Select Processing (enter 0 or 1)

 flagContr = 1;

 flagReso = 0;

 flagNombre = 0;

 flagOptMinMaxAuto = 1;

 flagOptMinMax = 0;

 flagRenumFrom1 = 1;

 flagRenumATMT = 0;

 

各パラメータも基本的にダイアログではなく、あらかじめ打ち込んでおくタイプなので、コード内を探して変更してください。

(解像度変更の設定dpiとか)

 

保存先フォルダは、とりあえずどんなPCでも動作する(はず)なので「ダウンロード先フォルダ」にしています。

自分の好きな場所に変更すると、より使いやすいと思います。 

 

 

各機能の解説

 

各処理の細かな解説は、以下のページを参考にしてみてください。

 

 ・Contrast Adjustment

コントラスト・濃度を調整するMacro - その漫画自炊オタクはImageJマクロに恋をする

 

 ・Optimize Min And Max [Manual] 

コントラスト調整に必要なMax値とMin値を自動で求めるためのMacro - その漫画自炊オタクはImageJマクロに恋をする

 

 ・Change the Resolution

解像度を変更するMacro - その漫画自炊オタクはImageJマクロに恋をする

  

 ・Nombre Cut

実用版!ノンブル領域を削除し, コントラスト調整, 解像度変更も一括で行えるMacro - その漫画自炊オタクはImageJマクロに恋をする

 

・Renumbering [from 1] 

【多目的】コントラスト調整やリサイズ処理などなどを、一気にやってしまうためのMacro - その漫画自炊オタクはImageJマクロに恋をする

 

 ・Renumbering [Automator]

【Mac】実用版!PDFからJPEGに変換した画像のコントラスト調整+フォルダ収納のためのMacro - その漫画自炊オタクはImageJマクロに恋をする

 

 

 

 

 

 

 

ライセンスなんかは一切無いので、ぜひぜひ自由に使ってみてください!

  

imagej-jisui.hatenablog.com