week 4 ++ more image process
|
contrast stretching ( code) :
the idea is to find the lower and upper gray bound for an image and then stretch them to white and black.
I actually did this in three steps, though I probably could have condensed it down.
1 - make histogram of original image
2 - make histogram only of the range of the original
3 - now stretch it out into a new full-sized histogram
though the actual drawn final image doesn't require this 3-step process,
and actually I had some trouble getting the lower gray bound to work.
|
/* from the update() */
float pctX = (float)mouseX / (float)ofGetWidth();
float pctY = (float)mouseY / (float)ofGetHeight();
for (int i = 0; i < texW; i++){
for (int j = 0; j < texH; j++){
// -- 2-image multiplying (variable) --
int t_var = int(pctY*(num_img - 2));
float per_multi = float(Pixels[t_var][j * texW + i])/255.0f;
TexPixels[0][j * texW + i] = (unsigned char)(MIN(255*pctX,
Pixels[t_var + 1][j * texW + i] * per_multi));
}
}
for(int t = 0; t < 2; t++){
// get the pixels into the texture
Textures[t].loadData(TexPixels[t], texW,texH, GL_LUMINANCE);
}
// -- HISTOGRAMS :: CALCULATE --
for(int h = 0; h < 255; h++){
Histogram0[h] = 0;
Histogram1[h] = 0;
}
hist_max0 = 0;
hist_max1 = 0;
hist_maxX = 0;
hist_lobound = 0;
hist_hibound = 255;
for (int i = 0; i < texW; i++){
for (int j = 0; j < texH; j++){
for(int h = 0; h < 255; h++){
// -- plot histogram of original
if(TexPixels[0][j * texW + i] == h){
Histogram0[h]++;
}
hist_max0 = MAX(hist_max0, Histogram0[h]);
}
}
}
for(int h = 0; h < 255; h++){
// -- calculate bounds / range of original histogram
if(Histogram0[h] == 0){
//hist_lobound = MAX(hist_lobound, h); // <-- this needs work
hist_hibound = MIN(hist_hibound, h);
}
hist_range = hist_hibound - hist_lobound;
}
// -- temporary histogram space
for(int h = 0; h < hist_range; h++){
HistogramX[h] = Histogram0[h + hist_lobound];
hist_maxX = MAX(hist_maxX, HistogramX[h]);
}
// --
for(int h = 0; h < 255; h++){
Histogram1[h] = HistogramX[int(floor(h * hist_range / 255))];
hist_max1 = MAX(hist_max1, Histogram1[h]);
}
// -- write stretched image
for (int p = 0; p < texW * texH; p++){
TexPixels[1][p] = (TexPixels[0][p] - hist_lobound)*(255 / hist_range);
}
|
|
histograms of blended images ( code) :
two different histograms of two blended images from the last assignment
|
/* in the update() */
float pctX = (float)mouseX / (float)ofGetWidth();
float pctY = (float)mouseY / (float)ofGetHeight();
for (int i = 0; i < texW; i++){
for (int j = 0; j < texH; j++){
for (int k=0; k < num_img; k++){
// -- contrasting (variable) --
if (Pixels[k][j * texW + i] > 127){
TexPixels[1][j * texW + i] = MIN(255,
TexPixels[1][j * texW + i] + (inv_img) * Pixels[k][j * texW + i] + 255*pctX);
}else{
TexPixels[1][j * texW + i] = MAX(0,
TexPixels[1][j * texW + i] - (inv_img) * Pixels[k][j * texW + i] - 255*pctY);
}
// -- contrasting + thresholding (variable) --
if (Pixels[k][j * texW + i] > int(255*pctY)){
TexPixels[2][j * texW + i] = MIN(255,
TexPixels[2][j * texW + i] + (inv_img) * Pixels[k][j * texW + i] + 255*pctX);
}else{
TexPixels[2][j * texW + i] = MAX(0,
TexPixels[2][j * texW + i] - (inv_img) * Pixels[k][j * texW + i] - 255*pctX);
}
}
}
}
for(int t = 1; t < 3; t++){
// get the pixels into the texture
Textures[t].loadData(TexPixels[t], texW,texH, GL_LUMINANCE);
}
// -- HISTOGRAMS :: CALCULATE --
for(int h = 0; h < 255; h++){
Histogram0[h] = Histogram1[h] = Histogram2[h] = Histogram3[h] = 0;
}
hist_max0 = hist_max1 = hist_max2 = hist_max3 = 0;
for (int i = 0; i < texW; i++){
for (int j = 0; j < texH; j++){
for(int h = 0; h < 255; h++){
/*if(TexPixels[0][j * texW + i] == h){;
Histogram0[h]++;
}
hist_max0 = MAX(hist_max0, Histogram0[h]);
*/
if(TexPixels[1][j * texW + i] == h){;
Histogram1[h]++;
}
hist_max1 = MAX(hist_max1, Histogram1[h]);
if(TexPixels[2][j * texW + i] == h){;
Histogram2[h]++;
}
hist_max2 = MAX(hist_max2, Histogram2[h]);
}
}
}
|
|
directions... NSEW ( code) :
getting pixels to change based on neighboring pixel criteria
(dilation, erosion, and I threw in edge detection).
not bad, although the effect is pretty subtle and the screens don't really do it justice,
so you can open them in a new window to see a little more detail but even then it's almost a neglible effect,
which means that we'll have to think of dynamically expanding the neighboring pixel range, some radius.
- erosion
- dilation
- edge detection
|
/* in the update() */
// -- variable thresholding
int pctX = 255*mouseX/1500;
for (int i = 0; i < imageW*imageH; i++){
if(pixelsA[i] > pctX){
pixelsB[i] = 255;
}
if(pixelsA[i] <= pctX){
pixelsB[i] = 0;
}
}
// -- erosion -- black, black, black
/*
unsigned char test_me = 255;
unsigned char test_nbor = 255;
unsigned char test_true = 255;
unsigned char test_false = 0;
*/
// -- dilation -- black, white, white
/*
unsigned char test_me = 0;
unsigned char test_nbor = 0;
unsigned char test_true = 0;
unsigned char test_false = 255;
*/
// -- edge detection -- black, white, black
unsigned char test_me = 0;
unsigned char test_nbor = 255;
unsigned char test_true = 255;
unsigned char test_false = 0;
// -- pixel testing NSEW
for (int i = 1; i < imageW - 1; i++){
for (int j = 1; j < imageH - 1; j++){
int nw = (j - 1) * imageW + i - 1;
int w = (j - 0) * imageW + i - 1;
int sw = (j + 1) * imageW + i - 1;
int n = (j - 1) * imageW + i - 0;
int me = (j ) * imageW + i ;
int s = (j - 1) * imageW + i - 0;
int ne = (j - 1) * imageW + i + 1;
int e = (j - 0) * imageW + i + 1;
int se = (j + 1) * imageW + i + 1;
pixelsC[me] = pixelsB[me];
if(pixelsB[me] == test_me){
if( pixelsB[nw] == test_nbor ||
pixelsB[w] == test_nbor ||
pixelsB[sw] == test_nbor ||
pixelsB[n] == test_nbor ||
pixelsB[s] == test_nbor ||
pixelsB[ne] == test_nbor ||
pixelsB[e] == test_nbor ||
pixelsB[se] == test_nbor
){
pixelsC[me] = test_true;
}
else{
pixelsC[me] = test_false;
}
}
else{
pixelsC[me] = test_false;
}
}
}
|
|