Created
July 17, 2012 23:18
-
-
Save hiromiso/3132785 to your computer and use it in GitHub Desktop.
画像の縮小テスト
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <math.h> | |
#include <vector> | |
#include <opencv2/opencv.hpp> | |
// 最近傍法 | |
void NearestNeighbor(const IplImage *src, IplImage *dst) | |
{ | |
float wf = (double)src->width / dst->width; | |
float hf = (double)src->height / dst->height; | |
for (int y=0; y<dst->height; ++y) { | |
int sy = floor(hf * y + 0.5); | |
for (int x=0; x<dst->width; ++x) { | |
int sx = floor(wf*x + 0.5); | |
dst->imageData[y*dst->width+x] = src->imageData[sy*src->width+sx]; | |
} | |
} | |
} | |
// 積分法 | |
void AreaAveraging(const IplImage *src, IplImage *dst) | |
{ | |
float ratio = (double)src->width * src->height / (dst->width * dst->height); | |
double ratiox = (double)src->width / dst->width; | |
double ratioy = (double)src->height / dst->height; | |
for (int y=0; y<dst->height; ++y) { | |
float rt = (double)y * ratioy; | |
float rb = (double)(y+1) * ratioy; | |
for (int x=0; x<dst->height; ++x) { | |
float rl = (double)x * ratiox; | |
float rr = (double)(x+1) * ratiox; | |
double pg(0.0); | |
for (int j=floor(rt); j<=floor(rb); ++j) { | |
float h; | |
if ((rt < j) && (j+1 < rb)) { | |
h = 1.0; | |
} | |
else if ((j <= rt) && (j+1 < rb)) { | |
h = 1.0 - (rt - j); | |
} | |
else if ((rt < j) && (rb <= j+1)) { | |
h = rb - j; | |
} | |
else { | |
h = rb - rt; | |
} | |
for (int i=floor(rl); i<=floor(rr); ++i) { | |
float w; | |
if ((rl < i) && (i+1 < rr)) { | |
w = 1.0; | |
} | |
else if ((i <= rl) && (i+1 < rr)) { | |
w = 1.0 - (rl - i); | |
} | |
else if ((rl < i) && (rr <= i+1)) { | |
w = rr - i; | |
} | |
else { | |
w = rr - rl; | |
} | |
pg += w * h * (unsigned char)src->imageData[j*src->width+i]; | |
} | |
} | |
dst->imageData[y*dst->width+x] = floor(pg / ratio + 0.5); | |
} | |
} | |
} | |
// Lanczos3 | |
inline float sinc(float p) | |
{ | |
return p == 0.0 ? 1.0 : sin(p * M_PI) / (p * M_PI); | |
} | |
inline float apply(float p) | |
{ | |
if (p < 0.0) { | |
p = -p; | |
} | |
return p < 3.0 ? sinc(p) * sinc(p / 3.0) : 0.0; | |
} | |
void makeWeight(int dw, float scale, std::vector<std::vector<float> > &weights) | |
{ | |
float fwidth = 3.0; | |
float width = fwidth / scale; | |
float fscale = 1.0 / scale; | |
int nums = (width * 2 + 1); | |
weights.resize(dw + 1); | |
for (int i=0; i<=dw; ++i) { | |
weights[i].resize(nums + 2); | |
} | |
for (int i=0; i<=dw; ++i) { | |
float center = (float)i / scale; | |
int left = floor(center - width); | |
int right = ceil(center + width); | |
for (int j=left; j<=right; ++j) { | |
weights[i][j-left] = apply((center - j) / fscale) / fscale; | |
} | |
} | |
} | |
void Lanczos3(const IplImage *src, IplImage *dst) | |
{ | |
if (dst->width == 0 || dst->height == 0) { | |
return; | |
} | |
IplImage *tmp; | |
std::vector<std::vector<float> > weights; | |
std::vector<int> lefts; | |
std::vector<int> rights; | |
float scale; | |
float width; | |
tmp = cvCreateImage(cvSize(dst->width, src->height), IPL_DEPTH_8U, 1); | |
if (src->width) { | |
scale = (float)dst->width / src->width; | |
} | |
else { | |
scale = (float)(dst->width - 1) / (src->width - 1); | |
} | |
width = 3.0 / scale; | |
makeWeight(dst->width, scale, weights); | |
lefts.resize(dst->width); | |
rights.resize(dst->width); | |
for (int x=0; x<dst->width; ++x) { | |
float center = (float)x / scale; | |
lefts[x] = floor(center - width); | |
rights[x] = ceil(center + width); | |
} | |
for (int y=0; y<src->height; ++y) { | |
for (int x=0; x<dst->width; ++x) { | |
int left = lefts[x]; | |
int right = rights[x]; | |
double s(0.0); | |
for (int j=left; j<=right; ++j) { | |
float cur = weights[x][j - left]; | |
int n = j < 0 ? -j : j; | |
n = j >= src->width ? src->width - j + src->width - 1 : n; | |
s += cur * (unsigned char)src->imageData[y*src->width+n]; | |
} | |
tmp->imageData[y*tmp->width+x] = std::min<int>(std::max<int>(s, 0), 255); | |
} | |
} | |
if (src->height == 1) { | |
scale = (float)dst->height / src->height; | |
} | |
else { | |
scale = (float)(dst->height - 1) / (src->height - 1); | |
} | |
width = 3.0 / scale; | |
makeWeight(dst->height, scale, weights); | |
lefts.resize(dst->height); | |
rights.resize(dst->height); | |
for (int y=0; y<dst->height; ++y) { | |
float center = (float)y / scale; | |
lefts[y] = floor(center - width); | |
rights[y] = ceil(center + width); | |
} | |
for (int x=0; x<dst->width; ++x) { | |
for (int y=0; y<dst->height; ++y) { | |
int left = lefts[y]; | |
int right = rights[y]; | |
double s(0.0); | |
for (int j=left; j<=right; ++j) { | |
float cur = weights[y][j - left]; | |
int n = j < 0 ? -j : j; | |
n = j >= tmp->height ? tmp->height - j + tmp->height - 1 : n; | |
s += cur * (unsigned char)tmp->imageData[n*tmp->width+x]; | |
} | |
dst->imageData[y*dst->width+x] = std::min<int>(std::max<int>(s, 0), 255); | |
} | |
} | |
} | |
int main(int argc, char* argv[]) | |
{ | |
IplImage *src; | |
IplImage *gry; | |
IplImage *dst; | |
src = cvLoadImage("test.jpg", CV_LOAD_IMAGE_ANYCOLOR); | |
gry = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1); | |
cvCvtColor(src, gry, CV_BGR2GRAY); | |
dst = cvCreateImage(cvSize(gry->width/5, gry->height/5), IPL_DEPTH_8U, 1); | |
NearestNeighbor(gry, dst); | |
cvSaveImage("test_nn.jpg", dst); | |
AreaAveraging(gry, dst); | |
cvSaveImage("test_aa.jpg", dst); | |
Lanczos3(gry, dst); | |
cvSaveImage("test_l3.jpg", dst); | |
cvReleaseImage(&src); | |
cvReleaseImage(&dst); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment