blob: 28f025f5350a8fd7ea6ccad703e49d0bd7488e28 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_NDEBUG 0
#define LOG_TAG "TestingImage"
#include <utils/Log.h>
#include <utils/Timers.h>
#include <string.h>
#include <cmath>
#include <vector>
#include <assert.h>
#include "vec3.h"
#include "testingimage.h"
const float GAMMA_CORRECTION = 2.2f;
// Constructs an instance with the given image byte array.
TestingImage::TestingImage(const unsigned char* inputImage,
int inputHeight, int inputWidth,
int inputChannel, int inputRowSpan) {
mImage = new unsigned char[inputRowSpan * inputHeight];
ALOGV("mImage format created! with size as %d, %d, %d",
inputRowSpan, inputHeight, inputChannel);
mWidth = inputWidth;
mHeight = inputHeight;
mChannels = inputChannel;
mRowSpan = mWidth * mChannels;
for (int i = 0; i < mHeight; ++i) {
for (int j = 0; j < mWidth; ++j) {
for (int k = 0; k < mChannels; ++k) {
mImage[i * mRowSpan + j* mChannels + k] =
inputImage[i * inputRowSpan + j * inputChannel + k];
}
}
}
ALOGV("mImage converted!");
}
// Constructs an instance with the given image and resize it to a new size.
TestingImage::TestingImage(const unsigned char* inputImage,
int inputHeight, int inputWidth,
int inputChannel, int inputRowSpan,
int newHeight, int newWidth) {
mImage = new unsigned char[newHeight * newWidth * inputChannel];
ALOGV("mImage format created! with size as %d, %d, %d",
newHeight, newWidth, inputChannel);
mHeight = newHeight;
mWidth = newWidth;
mChannels = inputChannel;
mRowSpan = mWidth * mChannels;
// Computes how many pixels in the original image corresponds to one pixel
// in the new image.
int heightScale = inputHeight / newHeight;
int widthScale = inputWidth / newWidth;
// Average the corresponding pixels in the original image to compute the
// pixel value of the new image.
for (int i = 0; i < mHeight; ++i) {
for (int j = 0; j < mWidth; ++j) {
for (int k = 0; k < mChannels; ++k) {
int pixelValue = 0;
for (int l = 0; l < heightScale; ++l) {
for (int m = 0; m < widthScale; ++m) {
pixelValue += inputImage[
(i * heightScale + l) * inputRowSpan
+ (j * widthScale + m) * inputChannel + k];
}
}
pixelValue = pixelValue / (heightScale * widthScale);
mImage[i * mRowSpan + j * mChannels + k] =
(unsigned char) pixelValue;
}
}
}
}
TestingImage::~TestingImage() {
if (mImage!=NULL) {
delete[] mImage;
}
}
int TestingImage::getPixelValue(int row, int column, int channel) const {
assert ((row >= 0) && (row < mHeight));
assert ((column >= 0) && (column < mWidth));
assert ((channel >= 0) && (channel < mChannels));
return (int)mImage[row * mRowSpan + column * mChannels + channel];
}
Vec3i TestingImage::getPixelValue(int row, int column) const {
Vec3i current_color(getPixelValue(row, column, 0),
getPixelValue(row, column, 1),
getPixelValue(row, column, 2));
return current_color;
}
Vec3i TestingImage::getPixelValue(const Vec2i &pixelPosition) const {
return getPixelValue(pixelPosition.x(), pixelPosition.y());
}
Vec3i TestingImage::getPixelValue(const Vec2f &pixelPosition) const {
return getPixelValue(static_cast<int>(pixelPosition.x()),
static_cast<int>(pixelPosition.y()));
}
// Returns a vector of the colors in the requested block of color checkers.
// The vector is formatted by going through the block from left to right and
// from top to bottom.
const std::vector<Vec3f>* TestingImage::getColorChecker(
int rowStart, int rowEnd, int columnStart, int columnEnd,
const std::vector<std::vector< Vec2f > >* centerAddress,
const std::vector<std::vector< float > >* radiusAddress) const {
std::vector<Vec3f>* checkerColors = new std::vector<Vec3f>;
// Average the pixel values of the pixels within the given radius to the
// given center position.
for (int i = rowStart; i < rowEnd; ++i) {
for (int j = columnStart; j < columnEnd; ++j) {
float radius = sqrt((*radiusAddress)[i][j]);
Vec2f center((*centerAddress)[i][j].x(),
(*centerAddress)[i][j].y());
Vec3f meanColor(0.f, 0.f, 0.f);
int numPixels = 0;
for (int ii = static_cast<int>(center.x() - radius);
ii < static_cast<int>(center.x() + radius); ++ii) {
for (int jj = static_cast<int>(center.y() - radius);
jj < static_cast<int>(center.y() + radius); ++jj) {
Vec2i pixelPosition(ii,jj);
if (pixelPosition.squareDistance<float>(center) <
(*radiusAddress)[i][j]) {
meanColor = meanColor + getPixelValue(pixelPosition);
++numPixels;
}
}
}
meanColor = meanColor / numPixels;
checkerColors->push_back(meanColor);
}
}
return checkerColors;
}
bool TestingImage::rgbToGrayScale(unsigned char* grayLayer) const {
if (mChannels == 4) {
for (int i = 0; i < mWidth; i++) {
for (int j = 0; j < mHeight; j++) {
float redLinear = pow(getPixelValue(j, i, 0),
GAMMA_CORRECTION);
float greenLinear = pow(getPixelValue(j,i,1),
GAMMA_CORRECTION);
float blueLinear = pow(getPixelValue(j,i,2),
GAMMA_CORRECTION);
// Computes the luminance value
grayLayer[j * mWidth + i] =
(unsigned char)((int)pow((0.299f * redLinear
+ 0.587f * greenLinear
+ 0.114f * blueLinear),
1/GAMMA_CORRECTION));
}
}
return true;
} else {
return false;
}
}