#include "stdafx.h"
//-------------------------------------------------------------------------------
// 行列を標準出力に表示
void GShowMat(const CvMat *mat, const char *name, const char *format)
{
printf("%s[%d,%d] = \n", name, mat->rows, mat->cols);
for(int row = 0; row < mat->rows && row < SHOW_MAX_ROW; row ++)
{
printf("");
for(int col=0; col<mat->cols; col ++)
{
CvScalar v = cvGet2D(mat, row, col);
printf(format, v.val[0]);
if (col < mat->cols - 1) printf(", ");
}
printf("\n");
}
if (mat->rows > SHOW_MAX_ROW) printf("continue....\n");
printf("\n");
}
//-------------------------------------------------------------------------------
// ファイルの有無を判定する
bool GFileExists(const char *path)
{
WIN32_FIND_DATA ffd;
return (FindFirstFile(path, &ffd) != INVALID_HANDLE_VALUE);
}
//-------------------------------------------------------------------------------
// 任意チャネル,任意形式の行列からデータを取り出す
double GcvmGet(const CvMat *mat, const int row, const int col, const int ch)
{
CvScalar v = cvGet2D(mat, row, col);
return v.val[ch];
}
//-------------------------------------------------------------------------------
// 縮小を伴う画像表示(必要ならウインドウ生成も行う)
int GShowImage(const IplImage *img, const int num, const char *title,
const int wait)
{
static int numDisp = 0;
if (num < 1) return numDisp;
// 表示画像生成
IplImage *show = cvCreateImage(cvSize(DISP_W, DISP_H),
img->depth, img->nChannels);
if (img->depth == IPL_DEPTH_8U) cvResize(img, show);
else GcvResizeD(img, show);
// タイトル描画
char titleM[256];
sprintf_s(titleM, sizeof(titleM), "%s%s", title,
(wait < 1 ? " [WAIT]" : ""));
CvFont font;
CvSize textSize;
int baseline;
cvInitFont(&font, CV_FONT_HERSHEY_COMPLEX, 0.7, 0.7, 0, 1);
cvGetTextSize(titleM, &font, &textSize, &baseline);
cvRectangle(show, cvPoint(0, 0),
cvPoint(textSize.width + 10, textSize.height + 10), cvScalarAll(0),
CV_FILLED);
cvPutText(show, titleM, cvPoint(5, textSize.height + 5), &font, cvScalarAll(255));
// ウインドウ作成
char dispname[256];
while (numDisp < num)
{
numDisp ++;
sprintf_s(dispname, sizeof(dispname), "解析結果 %d", numDisp);
cvNamedWindow(dispname);
}
// 表示
sprintf_s(dispname, sizeof(dispname), "解析結果 %d", num);
cvShowImage(dispname, show);
int key = cvWaitKey(wait);
if (key == 27) exit(1);
SAFE_RELEASEIMG(show);
return key;
}
//-------------------------------------------------------------------------------
// 浮動小数点データに対応した画像リサイズ(最近傍法)
void GcvResizeD(const IplImage *src, IplImage *dst)
{
const double xScale = (double)dst->width / (double)src->width;
const double yScale = (double)dst->height / (double)src->height;
double max, min, gmax, gmin, sc;
// 正規化のための最大,最小値検索
if (src->nChannels > 1)
{
IplImage *ch0 = cvCreateImage(cvGetSize(src), src->depth, 1);
IplImage *ch1 = cvCreateImage(cvGetSize(src), src->depth, 1);
IplImage *ch2 = cvCreateImage(cvGetSize(src), src->depth, 1);
cvSplit(src, ch0, ch1, ch2, NULL);
cvMinMaxLoc(ch0, &gmin, &gmax);
cvMinMaxLoc(ch1, &min, &max);
gmin = (min < gmin ? min : gmin);
gmax = (max > gmax ? max : gmax);
cvMinMaxLoc(ch2, &min, &max);
gmin = (min < gmin ? min : gmin);
gmax = (max > gmax ? max : gmax);
SAFE_RELEASEIMG(ch0);
SAFE_RELEASEIMG(ch1);
SAFE_RELEASEIMG(ch2);
}
else
{
cvMinMaxLoc(src, &gmin, &gmax);
}
sc = 2.0 / (gmax - gmin);
// OpenMPでスケーリング
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for (int dy = 0; dy < dst->height; dy ++)
{
for (int dx = 0; dx < dst->width; dx ++)
{
int sx = (int)((double)dx / xScale + 0.5);
int sy = (int)((double)dy / yScale + 0.5);
sx = sx >= src->width ? src->width - 1 : sx;
sy = sy >= src->height ? src->height - 1 : sy;
CvScalar v = cvGet2D(src, sy, sx);
v = cvScalar((v.val[0] - gmin) * sc,
(v.val[1] - gmin) * sc,
(v.val[2] - gmin) * sc);
cvSet2D(dst, dy, dx, v);
}
}
}
//-------------------------------------------------------------------------------
// CSVファイルを読み込んで行列を生成する
//
// const char *filename CSVファイル名
// const int rows 読み込む行数
// const int cols 読み込む列数
// const int startRow 読み込み開始行(1から数える)
// const int startCol 読み込み開始列(1から数える)
//
CvMat *GLoadCsv(const char *filename, const int rows, const int cols,
const int startRow, const int startCol)
{
// CSVファイルを開く
FILE *fp;
fopen_s(&fp, filename, "r");
if (!fp)
{
printf("Can't open csv file: %s\n", filename);
return NULL;
}
// 読み込みバッファの準備
char buffer[1024];
CvMat *mat = cvCreateMat(rows, cols, CV_64F);
int readRow = 0, readCol = 0;
// データ読み込み
for (int row = 0; row < rows + startRow - 1; row ++)
{
fgets(buffer, sizeof(buffer), fp);
char *begin = buffer;
if (row < startRow - 1) continue;
readCol = 0;
for (int col = 0; col < cols + startCol - 1; col ++)
{
char *pt = begin;
for (; *pt != ',' && *pt != '\n' && *pt != '\0'; pt ++);
if (*pt == '\0')
{
printf("Csv file error: %s\n", filename);
return NULL;
}
*pt = '\0';
if (col >= startCol - 1)
{
cvmSet(mat, readRow, readCol, atof(begin));
readCol ++;
}
begin = pt + 1;
}
readRow ++;
}
// ファイルを閉じる
fclose(fp);
// データ表示
#ifdef SHOW_FILELOAD
GShowMat(mat, filename, "%8.4f");
#endif // SHOW_FILELOAD
return mat;
}
//-------------------------------------------------------------------------------
// 画像の数値データを標準出力にダンプ表示
void GImageDumpD(const IplImage *src, const int num, const char *name,
const char *format)
{
if (src->depth != IPL_DEPTH_64F) return;
printf("Image dump '%s'\n", name);
for (int i = 0; i < num; i ++)
{
double val = *(((double*)src->imageData)+i);
printf(format, val);
printf(", ");
}
printf("\n");
}
//-------------------------------------------------------------------------------
// 文字列をトリミングする
// 文字列にNULLを書き込む(末尾位置が変わる)ので注意
void GTrimStr(char **buf)
{
for (; GIsSpace(**buf); *buf ++);
char *pt;
for (pt = *buf + strlen(*buf) - 1; GIsSpace(*pt) && pt >= *buf; pt --);
pt ++;
if (GIsSpace(*pt)) *pt = '\0';
}
//-------------------------------------------------------------------------------
// 文字が空白系の文字(タブ,改行含む)かどうか
bool GIsSpace(const char ch)
{
return (strchr(" \t\r\n", ch) != NULL);
}
//-------------------------------------------------------------------------------
// OpenMP を使ったMatMul
// 注意:cvMatMul より劇的に遅いので使えない (cvmGet/Set のせい?)
void GcvPMatMul(const CvMat *src1, const CvMat *src2, CvMat *dst)
{
// 行列サイズチェック
assert( src1->cols == src2->rows );
const bool mode = (src1->rows < src2->cols);
const int nLoop1 = mode ? src2->cols : src1->rows;
const int nLoop2 = !mode ? src2->cols : src1->rows;
//const double *data1 = (double*)src1->data.db;
//const double *data2 = (double*)src2->data.db;
//double *dataD = (double*)dst ->data.db;
// OpenMPで外ループを並列処理
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic)
#endif
for (int loop1 = 0; loop1 < nLoop1; loop1 ++)
{
for (int loop2 = 0; loop2 < nLoop2; loop2 ++)
{
const int r1 = mode ? loop2 : loop1;
const int c2 = mode ? loop1 : loop2;
double sum = 0;
for (int i = 0; i < src1->cols; i ++)
sum += cvmGet(src1, r1, i) * cvmGet(src2, i, c2);
cvmSet(dst, r1, c2, sum);
// sum += data1[r1 * src1->cols + i] * data2[i * src2->cols + c2];
//dataD[r1 * dst->cols + c2] = sum;
}
}
}
//-------------------------------------------------------------------------------
// 画像にガンマを掛ける
IplImage *GGenAddGamma(const IplImage *img)
{
IplImage *gamma = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, COLOR);
const double g = 1.0 / 2.2;
int idx = 0;
for (int y = 0; y < img->height; y ++)
{
for (int x = 0; x < img->width; x ++)
{
CvScalar v = cvGet2D(img, y, x);
for (int c = 0; c < COLOR; c ++)
{
v.val[c] = pow(v.val[c] * 1000.0, g);
v.val[c] = v.val[c] < 0 ? 0 : (v.val[c] > 255.0 ? 255.0 : v.val[c]);
gamma->imageData[idx ++] = (BYTE)v.val[c];
}
}
}
return gamma;
}
CvScalar GXYZtoLab(CvScalar xyz)
{
// 関数内だけで使用できるローカル関数を定義
struct local {
static double F(double x)
{ return x > 0.008856 ? pow(x, 1.0/3.0) : 7.787 * x + (16.0/116.0); }
};
double white[3] = {92.219, 100.0, 95.965};
double fx = local::F(xyz.val[0] / white[0]);
double fy = local::F(xyz.val[1] / white[1]);
double fz = local::F(xyz.val[2] / white[2]);
CvScalar lab;
lab.val[0] = 116.0 * fy - 16.0;
lab.val[1] = 500.0 * (fx - fy);
lab.val[2] = 200.0 * (fy - fz);
return lab;
}