LUV getSampleColor(PICTURE picture, int ex, int ey, int ew) { int j, i; // サンプルエリア スタート座標 int sx = ex - ew / 2; int sy = ey - (int)(2.5f * (float)ew); // サンプルカラーの取得 unsigned int rgb; XYZ xyz; LUV *area; LUV sample = {0.0f, 0.0f, 0.0f}; int num = 0; area = (LUV *)malloc(ew / 2 * ew * sizeof(LUV)); // サンプルエリアの重心を計算 for (j = 0; j < ew / 2; j++) { for (i = 0; i < ew; i++) { rgb = picture.pixels[(j + sy) * picture.width + (i + sx)]; xyz = RGBtoXYZ(rgb); area[j * ew + i] = XYZtoLUV(xyz); sample.L = (sample.L * (float)num + area[j * ew + i].L) / ((float)num + 1.0f); sample.u = (sample.u * (float)num + area[j * ew + i].u) / ((float)num + 1.0f); sample.v = (sample.v * (float)num + area[j * ew + i].v) / ((float)num + 1.0f); num++; } } // 重心からの距離を計算 float *dst; float min = 99999.0f; dst = (float *)malloc(num * sizeof(float)); for (i = 0; i < ew / 2 * ew; i++) { dst[i] = (area[i].L - sample.L) * (area[i].L - sample.L) + (area[i].u - sample.u) * (area[i].u - sample.u) + (area[i].v - sample.v) * (area[i].v - sample.v); dst[i] = (float)sqrt(dst[i]); if (dst[i] < min) min = dst[i]; } // 重心に近いものだけでサンプルカラーを再計算 sample.L = 0.0f; sample.u = 0.0f; sample.v = 0.0f; num = 0; for (i = 0; i < ew / 2 * ew; i++) { if (min * 3.0f > dst[i]) { sample.L = (sample.L * (float)num + area[i].L) / ((float)num + 1.0f); sample.u = (sample.u * (float)num + area[i].u) / ((float)num + 1.0f); sample.v = (sample.v * (float)num + area[i].v) / ((float)num + 1.0f); num++; } } free(area); free(dst); return sample; }
void ColorSpace::RGBtoXYZ (CoImage* pIn, CoImage* pOut) { assert (pIn->GetType() == MAT_Tbyte); assert (pOut->GetType() == MAT_Tfloat); BYTE** ppbR = pIn->m_matX.data.ptr; BYTE** ppbG = pIn->m_matY.data.ptr; BYTE** ppbB = pIn->m_matZ.data.ptr; float** pprX = pOut->m_matX.data.fl; float** pprY = pOut->m_matY.data.fl; float** pprZ = pOut->m_matZ.data.fl; for (int iH = 0; iH < pIn->GetHeight(); iH ++) for (int iW = 0; iW < pIn->GetWidth(); iW ++) { RGBtoXYZ(ppbR[iH][iW], ppbG[iH][iW], ppbB[iH][iW], &pprX[iH][iW], &pprY[iH][iW], &pprZ[iH][iW]); } }
JNIEXPORT void JNICALL Java_jp_dego_sample_ipcv_MainActivity_checkColorSpace(JNIEnv *env, jobject obj, jobject bmp) { AndroidBitmapInfo info; void* pixels; // Bitmapの情報を取得 if (AndroidBitmap_getInfo(env, bmp, &info) < 0) return; // Bitmapのフォーマットをチェック if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) return; // Bitmapをロック if (AndroidBitmap_lockPixels(env, bmp, &pixels) < 0) return; int i, j; jint *p = pixels; for (j = 0; j < info.height; j++) { for (i = 0; i < info.width; i++) { ARGB argb = {0, 0, 0, 0}; argb.red = getR(p[j * info.width + i]); argb.green = getG(p[j * info.width + i]); argb.blue = getB(p[j * info.width + i]); XYZ xyz; // LUV luv; // RGBtoXYZ(&argb, &xyz); // XYZtoLUV(&xyz, &luv); // LUVtoXYZ(&luv, &xyz); // XYZtoRGB(&xyz, &argb); LAB lab; RGBtoXYZ(&argb, &xyz); XYZtoLAB(&xyz, &lab); LABtoXYZ(&lab, &xyz); XYZtoRGB(&xyz, &argb); p[j * info.width + i] = createColorFromARGB(argb); } } }
void AcesInputFile::Data::initColorConversion () { const Header &header = rgbaFile->header(); Chromaticities fileChr; if (hasChromaticities (header)) fileChr = chromaticities (header); V2f fileNeutral = fileChr.white; if (hasAdoptedNeutral (header)) fileNeutral = adoptedNeutral (header); const Chromaticities acesChr = acesChromaticities(); V2f acesNeutral = acesChr.white; if (fileChr.red == acesChr.red && fileChr.green == acesChr.green && fileChr.blue == acesChr.blue && fileChr.white == acesChr.white && fileNeutral == acesNeutral) { // // The file already contains ACES data, // color conversion is not necessary. return; } mustConvertColor = true; minX = header.dataWindow().min.x; maxX = header.dataWindow().max.x; // // Create a matrix that transforms colors from the // RGB space of the input file into the ACES space // using a color adaptation transform to move the // white point. // // // We'll need the Bradford cone primary matrix and its inverse // static const M44f bradfordCPM (0.895100, -0.750200, 0.038900, 0.000000, 0.266400, 1.713500, -0.068500, 0.000000, -0.161400, 0.036700, 1.029600, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000); const static M44f inverseBradfordCPM (0.986993, 0.432305, -0.008529, 0.000000, -0.147054, 0.518360, 0.040043, 0.000000, 0.159963, 0.049291, 0.968487, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000); // // Convert the white points of the two RGB spaces to XYZ // float fx = fileNeutral.x; float fy = fileNeutral.y; V3f fileNeutralXYZ (fx / fy, 1, (1 - fx - fy) / fy); float ax = acesNeutral.x; float ay = acesNeutral.y; V3f acesNeutralXYZ (ax / ay, 1, (1 - ax - ay) / ay); // // Compute the Bradford transformation matrix // V3f ratio ((acesNeutralXYZ * bradfordCPM) / (fileNeutralXYZ * bradfordCPM)); M44f ratioMat (ratio[0], 0, 0, 0, 0, ratio[1], 0, 0, 0, 0, ratio[2], 0, 0, 0, 0, 1); M44f bradfordTrans = bradfordCPM * ratioMat * inverseBradfordCPM; // // Build a combined file-RGB-to-ACES-RGB conversion matrix // fileToAces = RGBtoXYZ (fileChr, 1) * bradfordTrans * XYZtoRGB (acesChr, 1); }
Imath::M44f XYZtoRGB (const Chromaticities chroma, float Y) { return RGBtoXYZ (chroma, Y).inverse(); }
void ColorSpace::RGBtoLab (BYTE bR, BYTE bG, BYTE bB, float *prL, float *pra, float *prb) { float rX, rY, rZ; RGBtoXYZ(bR, bG, bB, &rX, &rY, &rZ); XYZtoLab(rX, rY, rZ, prL, pra, prb); }
// ---------------------------------------------------------------------------- // 髪束を検出する手法 // ---------------------------------------------------------------------------- void getHairArea(PICTURE picture, int ex, int ey, int ew) { int w = picture.width; int h = picture.height; float *sobel = Sobel(picture); float *angle = SobelAngle(picture); float *like; // 髪らしさを表す変数 like = (float *)malloc(w * h * sizeof(float)); int i, j; for (i = 0; i < w * h; i++) { like[i] = 0.0f; // 初期化 } // カラー強度を取得 LUV sample = getSampleColor(picture, ex, ey, ew); float *cint = (float *)malloc(w * h * sizeof(float)); unsigned int rgb; XYZ xyz; LUV luv; float dst; float max, min; max = 0.0f; min = 9999999.9f; for (i = 0; i < w * h; i++) { rgb = picture.pixels[i]; xyz = RGBtoXYZ(rgb); luv = XYZtoLUV(xyz); dst = (sample.L - luv.L) * (sample.L - luv.L) + (sample.u - luv.u) * (sample.u - luv.u) + (sample.v - luv.v) * (sample.v - luv.v); dst = (float)sqrt(dst); if (max < dst) max = dst; if (min > dst) min = dst; cint[i] = dst; } for (i = 0; i < w * h; i++) { cint[i] = 1.0f - (cint[i] - min) / (max - min); } int x, y; float agl0, agl, diff, diff1, diff2; for (j = 2; j < h - 2; j++) { for (i = 2; i < w - 2; i++) { diff = 0.0f; for (y = -2; y < 3; y++) { for (x = -2; x < 3; x++) { diff1 = (float)abs(angle[j * w + i] - angle[(j + y) * w + (i + x)]); diff2 = (float)abs( 2.0f * M_PI - angle[j * w + i] - angle[(j + y) * w + (i + x)]); diff += diff1 < diff2 ? diff1 : diff2; } } like[j * w + i] = like[j * w + i] + diff / M_PI / 25.0f; // like[j * w + i] = like[j * w + i] + (1.0f - diff / 9.0f / M_PI) * cint[j * w + i]; // // 右回転 // y = j; // x = i; // agl0 = angle[j * w + i]; // while (0 <= y && y < h && 0 <= x && x < w && (x == i && y == j)) { // agl = angle[y * w + x]; // diff = abs(agl - agl0) < 2.0 * M_PI - abs(agl - agl0) ? // abs(agl - agl0) : 2.0 * M_PI - abs(agl - agl0); // if (diff > M_PI / 4.0) { // // 角度の差が45度以上の場合は累積しない // break; // } else { // like[j * w + i] = like[j * w + i] + 1.0f; // if (abs(agl0) < M_PI / 8.0) { // x++; // } else if (abs(agl0) < 3.0 * M_PI / 8.0) { // y++; // x++; // } else if (abs(agl0) < 5.0 * M_PI / 8.0) { // y++; // } else if (abs(agl0) < 7.0 * M_PI / 8.0) { // y++; // x--; // } else { // x++; // } // agl0 = agl; // } // } // // // 左回転 // y = j; // x = i; // agl0 = angle[j * w + i]; // while (0 <= y && y < h && 0 <= x && x < w && (x == i && y == j)) { // agl = angle[y * w + x]; // diff = abs(agl - agl0) < 2.0 * M_PI - abs(agl - agl0) ? // abs(agl - agl0) : 2.0 * M_PI - abs(agl - agl0); // if (diff > M_PI / 4.0) { // // 角度の差が45度以上の場合は累積しない // break; // } else { // like[j * w + i] = like[j * w + i] + 1.0f; // if (abs(agl0) < M_PI / 8.0) { // x--; // } else if (abs(agl0) < 3.0 * M_PI / 8.0) { // y--; // x--; // } else if (abs(agl0) < 5.0 * M_PI / 8.0) { // y--; // } else if (abs(agl0) < 7.0 * M_PI / 8.0) { // y--; // x++; // } else { // x--; // } // agl0 = agl; // } // } // i, j ループの最後 } } max = 0.0f; min = 99999.9f; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { if (max < like[j * w + i]) max = like[j * w + i]; if (min > like[j * w + i]) min = like[j * w + i]; } } unsigned int gray; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { gray = (unsigned int)((like[j * w + i] - min) / (max - min) * 255.0f); // gray = (unsigned int)(cint[j * w + i] * 255.0f); picture.pixels[j * w + i] = (0xFF000000 | gray << 16 | gray << 8 | gray); } } // float threshold = DAM(like, w * h, 255); // // for (i = 0; i < w; i++) { // if (like[i] < threshold) { // picture.pixels[i] = 0xFF000000; // } // } free(sobel); free(angle); free(cint); free(like); }
void Image::RGBtoLab(pixel4b *source, pixel3f *destination) { RGBtoXYZ(source, destination); XYZtoLab(destination); }
void convert(unsigned char *buf, int width, int height, int de) { double angle_chroma[360]; double angle_hue[360]; double angle_hue2[360]; double minchroma = 999; double maxchroma = 0; { int i; for (i = 0; i < 360; i++) { angle_chroma[i] = 9999; } double f; for (f = 0; f < 360; f += .25) { angle_hue[(int) ((angletohue(f) - angletohue(0)) / (angletohue(360) - angletohue(0)) * 360)] = f; angle_hue2[(int) f] = ((angletohue(f) - angletohue(0)) / (angletohue(360) - angletohue(0)) * 360); } double a; for (a = -80; a <= 80; a += .1) { int dir; for (dir = -1; dir <= 1; dir += 2) { double b = dir * 335.582 * exp(- a * a / (2 * 15.5723 * 15.5723)) / (15.5723 * sqrt(2 * M_PI)); double h = atan2(b, a); double c = sqrt(a * a + b * b); h -= 0.075; if (h < 0) { h += 2 * M_PI; } h = floor(h * 180 / M_PI); if (c < angle_chroma[(int) h]) { angle_chroma[(int) h] = c; } } } for (i = 0; i < 360; i++) { if (angle_chroma[i] < minchroma) { minchroma = angle_chroma[i]; } if (angle_chroma[i] > maxchroma) { maxchroma = angle_chroma[i]; } } } int *buf2 = malloc(width * height * 4 * sizeof(int)); int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { int r = buf[(y * width + x) * 4 + 0]; int g = buf[(y * width + x) * 4 + 1]; int b = buf[(y * width + x) * 4 + 2]; double X, Y, Z; double L, A, B; double C, H; RGBtoXYZ(r, g, b, &X, &Y, &Z); XYZtoLAB(X, Y, Z, &L, &A, &B); LABtoLCH(L, A, B, &L, &C, &H); if (H < 0) { H += 2 * M_PI; } if (de) { // desaturate C = C * minchroma / angle_chroma[(int) (H * 180 / M_PI)]; // shift hue int hh = (int) (H * 180 / M_PI + 720) % 360; H = angle_hue2[hh] * M_PI / 180; } else { // shift hue int hh = (int) (H * 180 / M_PI + 720) % 360; H = angle_hue[hh] * M_PI / 180; // resaturate C = C / minchroma * angle_chroma[(int) (H * 180 / M_PI)]; C *= minchroma / maxchroma; } LCHtoLAB(L, C, H, &L, &A, &B); LABtoXYZ(L, A, B, &X, &Y, &Z); XYZtoRGB(X, Y, Z, &r, &g, &b); buf2[(y * width + x) * 4 + 0] = r; buf2[(y * width + x) * 4 + 1] = g; buf2[(y * width + x) * 4 + 2] = b; } } int max = 0; for (x = 0; x < width * height; x++) { int i; for (i = 0; i < 3; i++) { if (buf2[x * 4 + i] > max) { max = buf2[x * 4 + i]; } } } for (x = 0; x < width * height; x++) { int i; for (i = 0; i < 3; i++) { buf[x * 4 + i] = buf2[x * 4 + i] * 255 / max; if (buf2[x * 4 + i] < 0) { buf[x * 4 + i] = 0; } } } }