www.pudn.com > PCA-SIFT.rar > image.cc


/* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */

/*

Author: Yan Ke
Dec 2003

*/

#include 
#include 
#include 
#include 
#include 


extern "C" {
     #include 
}

#include "config.h"
#include "image.h"

#define GAUSSKERN 4
#define PI 3.14159265358979323846

Image::Image(int width, int height) {
	newImage(width, height);
}

Image::Image(int width, int height, float * new_data) {
	assert(width > 0 && height > 0);

	this->width = width;
	this->height = height;
	
	pix = (float **) malloc(height * sizeof(float *));
	float * data = (float *) malloc(height * width * sizeof(float));

	for (int i = 0; i < height; i++) {
		pix[i] = data;
		data += width;
	}

	memcpy(*pix, new_data, width * height * sizeof(float));
}

Image::Image(const char * filename) {
	assert(filename);

	FILE* fp = fopen(filename, "rb");
	assert(fp);
	
	gray maxval;
	gray ** pixels;

	pixels = pgm_readpgm(fp, &width, &height, &maxval);
	
	fclose(fp);

	assert(pixels);
	
	newImage(width, height);
	
	for (int y = 0; y < height; y++) {
		for (int x = 0; x < width; x++)
			pix[y][x] = pixels[y][x] / 255.0;
	}

	pgm_freearray(pixels, height);
}

Image::~Image() {
	free(*pix);
	free(pix);
}

void Image::newImage(int width, int height) {
	assert(width > 0 && height > 0);

	this->width = width;
	this->height = height;
	
	pix = (float **) malloc(height * sizeof(float *));
	float * data = (float *) calloc(height * width, sizeof(float));

	for (int i = 0; i < height; i++) {
		pix[i] = data;
		data += width;
	}	
}

Image * Image::clone() {
	Image * im = new Image(width, height, *pix);
	return im;
}

Image * Image::halfSizeImage() {
	int w = width/2;
	int h = height/2;

	Image * im = new Image(w, h);
	
	for (int j = 0; j < h; j++) {
		for (int i = 0; i < w; i++) {
			im->setPixel(i, j, getPixel(i*2, j*2));
		}
	}

	return im;
}


Image * Image::doubleSizeImage() {
	int w = width*2;
	int h = height*2;

	Image * im = new Image(w, h);
	
	for (int j = 0; j < h; j++) {
		for (int i = 0; i < w; i++) {
			im->setPixel(i, j, getPixel(i/2, j/2));
		}
	}

	return im;
}


Image * Image::doubleSizeImage2() {
	int w = width*2;
	int h = height*2;

	Image * im = new Image(w, h);
	
	// fill every pixel so we don't have to worry about skipping pixels later
	for (int j = 0; j < h; j++) {
		for (int i = 0; i < w; i++) {
			im->setPixel(i, j, getPixel(i/2, j/2));
		}
	}

	/*
	  A B C
	  E F G
	  H I J

	  pixels A C H J are pixels from original image
	  pixels B E G I F are interpolated pixels

	*/

	// interpolate pixels B and I
	for (int j = 0; j < h; j += 2)
		for (int i = 1; i < w - 1; i += 2)
			im->setPixel(i, j, (getPixel(i/2, j/2) + getPixel(i/2 + 1, j/2)) / 2.0);

       
	// interpolate pixels E and G
	for (int j = 1; j < h - 1; j += 2)
		for (int i = 0; i < w; i += 2)
			im->setPixel(i, j, (getPixel(i/2, j/2) + getPixel(i/2, j/2 + 1)) / 2.0);

       
	// interpolate pixel F
	// interpolate pixels E and G
	for (int j = 1; j < h - 1; j += 2)
		for (int i = 1; i < w - 1; i += 2)
			im->setPixel(i, j, (getPixel(i/2, j/2) + getPixel(i/2, j/2 + 1)
					    + getPixel(i/2 + 1, j/2) + getPixel(i/2 + 1, j/2 + 1))
				     / 4.0);



	return im;
}


void Image::sub(Image * im2, Image * dst) {
	assert(im2);
	assert(dst);
	
	assert(width == im2->width && width == dst->width);
	assert(height == im2->height && height == dst->height);

	for (int j = 0; j < height; j++) {
		for (int i = 0; i < width; i++) {
			dst->setPixel(i, j, getPixel(i, j) - im2->getPixel(i, j));
		}
	}
	
}


void Image::write(const char * filename) {
	FILE * fp;
 
	assert(filename);
	fp = fopen(filename, "wb");
	assert(fp);

	gray ** pixels = pgm_allocarray(width, height);

	for (int j = 0; j < height; j++) {
		for (int i = 0; i < width; i++) {
			pixels[j][i] = (unsigned int) (getPixel(i, j) * 255.0);
		//unsigned int val = (unsigned int) (fabs(getPixel(i, j) * 255.0 * 20));
		//if (val > 255)
		//	val = 255;
		//pixels[j][i] = val;
		}
	}

	pgm_writepgm(fp, pixels, width, height, 255, 0);

	pgm_freearray(pixels, height);

	fclose(fp);

}

void Image::setPixel(int x, int y, float val) {
	assert(x >= 0 && x < width);
	assert(y >= 0 && y < height);
	//assert(val >= 0 && val <= 1);

	pix[y][x] = val;
}


float Image::getPixel(int x, int y) {
	assert(x >= 0 && x < width);
	assert(y >= 0 && y < height);

	return pix[y][x];
}

float Image::getPixelBI(float col, float row) {

	int irow, icol;
	float rfrac, cfrac;
	float row1 = 0, row2 = 0;
	
	irow = (int) row;
	icol = (int) col;
	
	if (irow < 0 || irow >= height
	    || icol < 0 || icol >= width)
		return 0;
	
	if (row > height - 1)
		row = height - 1;
	
	if (col > width - 1)
		col = width - 1;
	
	rfrac = 1.0 - (row - (float) irow);
	cfrac = 1.0 - (col - (float) icol);
	
	
	if (cfrac < 1) {
		row1 = cfrac * pix[irow][icol] + (1.0 - cfrac) * pix[irow][icol + 1];
	} else {
		row1 = pix[irow][icol];
	}
	
	if (rfrac < 1) {
		if (cfrac < 1) {
			row2 = cfrac * pix[irow+1][icol] + (1.0 - cfrac) * pix[irow+1][icol + 1];
		} else {
			row2 = pix[irow+1][icol];
		}
	}
	
	return rfrac * row1 + (1.0 - rfrac) * row2;
	

}

/**
 * Normalizes a matrix to unit length.
 * 
 * @param mat Matrix to normalize
 */

void normalizeMat(vector > & mat) {

	float sum = 0;

	for (unsigned int j = 0; j < mat.size(); j++) {
		for (unsigned int i = 0; i < mat[j].size(); i++) {
			assert(mat[j].size() == mat[0].size());
			sum += mat[j][i];
		}
	}

	for (unsigned int j = 0; j < mat.size(); j++) {
		for (unsigned int i = 0; i < mat[j].size(); i++) {
			mat[j][i] /= sum;
		}
	}

}

/**
 * Normalizes a vector to unit length.
 * 
 * @param vec vector to normalize
 */
void normalizeVec(vector & vec) {

	float sum = 0;

	for (unsigned int i = 0; i < vec.size(); i++)
		sum += vec[i];

	for (unsigned int i = 0; i < vec.size(); i++)
		vec[i] /= sum;
}

/**
 * Creates a 1D Gaussian kernel.
 * Kernel is always odd.
 *
 * @param sigma Sigma of Gaussian weighting function.
 * @return 1D Gaussian kernel
 */

vector GaussianKernel1D(float sigma) {

	assert (sigma > 0);

	int dim = (int) max(3.0f, 2 * GAUSSKERN * sigma + 1.0f);

	// make dim odd
	if (dim % 2 == 0)
		dim++;

	//printf("GaussianKernel1D(): Creating 1x%d vector for sigma=%.3f gaussian kernel\n", dim, sigma);

	vector kern(dim);

	float s2 = sigma * sigma;

	int c = dim / 2;
  
	for (int i = 0; i < (dim + 1) / 2; i++) {
		float v = 1 / (2 * PI * s2) * exp(-(i*i) / (2 * s2));
		kern[c+i] = v;
		kern[c-i] = v;
		
	}
	
	normalizeVec(kern);
	
	//for (unsigned int i = 0; i < kern.size(); i++)
	//	printf("%f\n", kern[i]);

	return kern;
}

/**
 * Convolve an image along the X direction at a particular pixel location.
 *
 * @param kernel Kernel to convolve with.
 * @param src Source image
 * @param x x pixel location
 * @param y y pixel location
 * @return Convolved value at location (x, y)
 */
float ConvolveLocWidth(vector & kernel, Image * src, int x, int y) {
	float pixel = 0;

	int cen = kernel.size() / 2;

	//printf("ConvolveLoc(): Applying convoluation at location (%d, %d)\n", x, y);

	for (unsigned int i = 0; i < kernel.size(); i++) {
		int col = x + (i - cen);
		if (col < 0)
			col = 0;
		if (col >= src->width)
			col = src->width - 1;

		float tmp = src->getPixel(col, y);
		pixel += kernel[i] * tmp;
	}

	if (pixel > 1)
		pixel = 1;

	return pixel;
}

/* Convolves an entire image along the X direction.
 * 
 * @param kern Kernel to convolve with.
 * @param src Source image
 * @param dst Destination image
 */
void Convolve1DWidth(vector & kern, Image * src, Image * dst) {
	for (int j = 0; j < src->height; j++) {
		for (int i = 0; i < src->width; i++) {
			//printf("%d, %d\n", i, j);
			dst->setPixel(i, j, ConvolveLocWidth(kern, src, i, j));
		}
	}
}

/**
 * Convolve an image along the Y direction at a particular pixel location.
 *
 * @param kernel Kernel to convolve with.
 * @param src Source image
 * @param x x pixel location
 * @param y y pixel location
 * @return Convolved value at location (x, y)
 */
float ConvolveLocHeight(vector & kernel, Image * src, int x, int y) {
	float pixel = 0;

	int cen = kernel.size() / 2;

	//printf("ConvolveLoc(): Applying convoluation at location (%d, %d)\n", x, y);

	for (unsigned int j = 0; j < kernel.size(); j++) {
		int row = y + (j - cen);

		if (row < 0)
			row = 0;
		if (row >= src->height)
			row = src->height - 1;

		float tmp = src->getPixel(x, row);
		pixel += kernel[j] * tmp;
	}

	if (pixel > 1)
		pixel = 1;

	return pixel;
}

/* Convolves an entire image along the Y direction.
 * 
 * @param kern Kernel to convolve with.
 * @param src Source image
 * @param dst Destination image
 */
void Convolve1DHeight(vector & kern, Image * src, Image * dst) {

	for (int j = 0; j < src->height; j++) {
		for (int i = 0; i < src->width; i++) {
			//printf("%d, %d\n", i, j);
			dst->setPixel(i, j, ConvolveLocHeight(kern, src, i, j));
		}
	}
}

void BlurImage(Image * src, Image * dst, float sigma) {
	assert (src && dst);

	assert(src->width == dst->width);
	assert(src->height == dst->height);

	Image * tmpImage = new Image(src->width, src->height);

	vector convkernel = GaussianKernel1D(sigma);

	/*
	printf("Gauss Blur for sigma %f: ", sigma);
	for (unsigned int i = 0; i < convkernel.size(); i++) {
		printf("%f ", convkernel[i]);
	}
	printf("\n");
	*/

	Convolve1DWidth(convkernel, src, tmpImage);
	Convolve1DHeight(convkernel, tmpImage, dst);
}

vector > GaussianKernel2D(float sigma) {
	int dim = (int) max(3.0f, GAUSSKERN * sigma);

	// make dim odd
	if (dim % 2 == 0)
		dim++;


	//printf("GaussianKernel(): Creating %dx%d matrix for sigma=%.3f gaussian\n", dim, dim, sigma);

	vector > mat;

	for (int i = 0; i < dim; i++) {
		vector row(dim);
		mat.push_back(row);
	}

	float s2 = sigma * sigma;

	int c = dim / 2;
  
	//printf("%d %d\n", mat.size(), mat[0].size());

	for (int i = 0; i < (dim + 1) / 2; i++) {
		for (int j = 0; j < (dim + 1) / 2; j++) {

			//printf("%d %d %d\n", c, i, j);

			float v = 1 / (2 * PI * s2) * exp(-(i*i + j*j) / (2 * s2));
			mat[c+i][c+j] = v;
			mat[c-i][c+j] = v;
			mat[c+i][c-j] = v;
			mat[c-i][c-j] = v;

			/*
			cvmSet(mat, c + i, c + j, v);
			cvmSet(mat, c - i, c + j, v);
			cvmSet(mat, c + i, c - j, v);
			cvmSet(mat, c - i, c - j, v);
			*/
		}
	}
	
	normalizeMat(mat);
	
	//printf("Done\n");
	//printmat(mat);

	return mat;
}