Skip to content

Commit

Permalink
Add Brightness / Contrast controls (#43)
Browse files Browse the repository at this point in the history
* add B/C controls, WIP for resulting images

* apply B/C to resulting images

make ComputeProbeValue_gs() B/C aware and use Konva's built-in filters

* add btn to reset B/C

* gui B/C: dont use listen() to allow num. type/edit

* add GlobalBC option for independent b/c control

* auto position opts window in bottom right

* minor clean up
  • Loading branch information
joedf authored Nov 15, 2023
1 parent fb20fcd commit c59584d
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 6 deletions.
27 changes: 23 additions & 4 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@
var G_GUI_Controller = new function() {
this.pixelCountX = 8;
this.pixelCountY = 8;
this.brightness = 0;
this.contrast = 0;
this.digitalMag = "1.00x";
this.advancedMode = false;
this.updateViews = function(){
Expand All @@ -95,6 +97,14 @@
G_Update_GroundTruth();
G_Update_InfoDisplays();
};
this.updateFilters = function(){ G_UpdateFilters(); },
this.globalBC = true;
this.resetBC = function(){
let cGui = G_GUI_Controller.controls;
cGui.brightness.setValue(0);
cGui.contrast.setValue(0);
G_UpdateFilters();
},
this.groundTruthImg = 'grains2tl.png';
this.pause_vSEM = G_VSEM_PAUSED;
this.doImageMetric = G_IMG_METRIC_ENABLED;
Expand All @@ -114,6 +124,16 @@
var gui_ip = gui.addFolder('Imaging Parameters');
gui_ip.add(G_GUI_Controller, 'pixelCountX', 1, 64, 1).onChange(G_GUI_Controller.updateViews);
gui_ip.add(G_GUI_Controller, 'pixelCountY', 1, 64, 1).onChange(G_GUI_Controller.updateViews);
G_GUI_Controller.controls.brightness = gui_ip
.add(G_GUI_Controller, 'brightness', -1, 1, 0.01)
.onChange(G_GUI_Controller.updateFilters);
G_GUI_Controller.controls.contrast = gui_ip
.add(G_GUI_Controller, 'contrast', -100, 100, 0.1)
.onChange(G_GUI_Controller.updateFilters);
gui_ip.add(G_GUI_Controller, 'globalBC')
.name('Global B/C')
.onChange(G_GUI_Controller.updateFilters);
gui_ip.add(G_GUI_Controller, 'resetBC').name('Reset Brightness / Contrast');
gui_ip.add(G_GUI_Controller, 'digitalMag').listen();
G_GUI_Controller.controls.pixelSize_nm = gui_ip
.add(G_GUI_Controller, 'pixelSize_nm', 1, 1000, 1).onChange(function(){
Expand Down Expand Up @@ -157,10 +177,9 @@
aboutBtn.name("About " + G_APP_NAME + " / Credits");
gui_io.open();

$("#options").append(gui.domElement).draggable({
// containment: 'body',
handle: '#options-handle',
});
$("#options").append(gui.domElement)
.position({at:'right bottom', my:'right bottom', of: '#options-anchor'})
.draggable({handle: '#options-handle'});

// used to auto-name the export files with a counter
var G_Export_img_count = 0;
Expand Down
5 changes: 3 additions & 2 deletions app/src/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,14 @@ summary {
#options-anchor {
display: inline-block;
position: fixed;
top: 35vh;
right: 0.25em;
bottom: 0;
right: 0;
z-index: 69;
user-select: none;
cursor: move;
width: 0;
height: 0;
margin: 2em 1em;
}

#options-full-resample {
Expand Down
33 changes: 33 additions & 0 deletions app/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* G_Update_InfoDisplays
* G_update_ImgMetrics
* G_UpdateRuler
* G_UpdateFilters
* G_AUTO_PREVIEW_LIMIT
* G_VSEM_PAUSED
* G_IMG_METRIC_ENABLED
Expand Down Expand Up @@ -88,6 +89,8 @@ var G_Update_InfoDisplays = null;
var G_update_ImgMetrics = null;
/** global reference to update the ruler */
var G_UpdateRuler = null;
/** global reference to update/apply image filters */
var G_UpdateFilters = null;

/** a global reference to the main body container that holds the boxes/stages.
* @todo do we still need this? Maybe remove... */
Expand Down Expand Up @@ -376,6 +379,36 @@ function OnImageLoaded(eImg, stages){
doUpdate();
});

function updateFilters(){
var doBC = Utils.getGlobalBCInput();
if (doBC) {
// stages that we want to apply filters to...
var fStages = [
groundtruthMapStage, baseImageStage,
spotContentStage, probeLayoutStage,
layoutSampledStage
];

// apply the filters
const brightness = Utils.getBrightnessInput();
const contrast = Utils.getContrastInput();
for (let i = 0; i < fStages.length; i++) {
const fStage = fStages[i];
let image = Utils.getFirstImageFromStage(fStage);
Utils.applyBrightnessContrast(image, brightness, contrast);
}

// for the resulting images, the sampling function, Utils.ComputeProbeValue_gs(),
// is made B/C aware and using Konva's built-in filters directly.
}

// call global visual update
doUpdate();
}
// update filters once immediately
updateFilters();
G_UpdateFilters = updateFilters;

doUpdate();

Utils.updateAdvancedMode();
Expand Down
51 changes: 51 additions & 0 deletions app/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ const Utils = {

getRowsInput: function(){ return G_GUI_Controller.pixelCountY; },
getColsInput: function(){ return G_GUI_Controller.pixelCountX; },
getBrightnessInput: function(){ return G_GUI_Controller.brightness; },
getContrastInput: function(){ return G_GUI_Controller.contrast; },
getGlobalBCInput: function(){ return G_GUI_Controller.globalBC; },
getCellWInput: function(){ return this.getInputValueInt($('#iCellW')); },
getCellHInput: function(){ return this.getInputValueInt($('#iCellH')); },
getSpotXInput: function(){ return this.getInputValueInt($('#iSpotX')); },
Expand Down Expand Up @@ -1504,6 +1507,17 @@ const Utils = {
// grab the pixel data from the pixel selection area
var pxData = ctx.getImageData(0,0,cv.width,cv.height);

// hack to directly use Konva's built-in filters code
if (typeof Konva != 'undefined') {
var brightnessFunc = Konva.Filters.Brighten.bind({
brightness: () => this.getBrightnessInput()});
var contrastFunc = Konva.Filters.Contrast.bind({
contrast: () => this.getContrastInput()});
// apply it directly to out image data before we sample it.
brightnessFunc(pxData);
contrastFunc(pxData);
}

// compute the average pixel (excluding 0-0-0-0 rgba pixels)
var pxColor = this.get_avg_pixel_gs(pxData);

Expand All @@ -1515,6 +1529,43 @@ const Utils = {
return pxColor;
},

/**
* Applies Brightness/Contrast (B/C) values to a given Konva stage or drawable.
* @param {*} drawable The Konva stage or drawable / drawElement.
* @param {*} brightness The brightness value, from -1 to 1.
* @param {*} contrast The contrast value, mainly from -100 to 100.
*/
applyBrightnessContrast: function(drawable, brightness=0, contrast=0) {
// cache step is need for filter effects to be visible.
// https://konvajs.org/docs/performance/Shape_Caching.html
drawable.cache();

// Filters: https://konvajs.org/api/Konva.Filters.html
// Brightness => https://konvajs.org/docs/filters/Brighten.html
// Contrast => https://konvajs.org/docs/filters/Contrast.html
var currentFilters = drawable.filters();
// null check, default to empty array if n/a.
currentFilters = currentFilters != null ? currentFilters : [];
// Add filter if not already included...
var currentFiltersByName = currentFilters.map(x => x.name);
var filtersToSet = currentFilters;
var added = 0;
['Brighten', 'Contrast'].forEach(filterName => {
if (!currentFiltersByName.includes(filterName)) {
filtersToSet.push(Konva.Filters[filterName]);
added++;
}
});
drawable.filters(filtersToSet);
if (G_DEBUG) {
console.log("filters added:", added);
}

// apply B/C filter values
drawable.brightness(brightness);
drawable.contrast(contrast);
},

/**
* Find and gets the first "image" type from the first layer of the given Konva stage
* @param {*} stage the stage to search through
Expand Down

0 comments on commit c59584d

Please sign in to comment.