// 画像ファイル → ImageLet public static Boolean MakeImageLet(Image imgTn, ImageLet imgLet) { // 定数計算(ImageLetの評価値は2x2分割決め打ちで取ってくるので、左上1/4を計算) const int iDh = DEF.LET_D / 2; int iXs = (DEF.TH_W - DEF.LET_D) / 2; int iYs = (DEF.TH_H - DEF.LET_D) / 2; int iXe = DEF.TH_W / 2; int iYe = DEF.TH_H / 2; // imgLetの生成 imgLet.bmData = new UMImage(DEF.LET_D, DEF.LET_D); // ビットマップに変換 Bitmap bmTn = new Bitmap(imgTn); double[] aR = new double[DEF.SQR(DEF.FIT_DELTA)]; double[] aG = new double[DEF.SQR(DEF.FIT_DELTA)]; double[] aB = new double[DEF.SQR(DEF.FIT_DELTA)]; for (int y = iYs; y < iYe; y++) { int yy = y - iYs; for (int x = iXs; x < iXe; x++) { int xx = x - iXs; // 画素値コピー Color[] aCol = new Color[] { bmTn.GetPixel(x, y), bmTn.GetPixel(x + iDh, y), bmTn.GetPixel(x, y + iDh), bmTn.GetPixel(x + iDh, y + iDh) }; imgLet.bmData.SetPixel(xx, yy, aCol[0]); imgLet.bmData.SetPixel(xx + iDh, yy, aCol[1]); imgLet.bmData.SetPixel(xx, yy + iDh, aCol[2]); imgLet.bmData.SetPixel(xx + iDh, yy + iDh, aCol[3]); // 平均用の積算 for (int a = 0; a < DEF.SQR(DEF.FIT_DELTA); a++) { aR[a] += aCol[a].R; aG[a] += aCol[a].G; aB[a] += aCol[a].B; } } } // 平均値算出 for (int a = 0; a < DEF.SQR(DEF.FIT_DELTA); a++) { imgLet.adAveR[a] += aR[a] / DEF.SQR(iDh); imgLet.adAveG[a] += aG[a] / DEF.SQR(iDh); imgLet.adAveB[a] += aB[a] / DEF.SQR(iDh); } return(true); }
public static int SelectImageLet(Color[] aCol, List <ImageLet> aImgLet, out double dDelta) { int iRet = 0; int iSeekMax = Math.Min(aImgLet.Count, DEF.SEEK_MAX); double dstMin = 0x0FFFFFFF; Object thisLock = new Object(); //for (int i = 0; i < iSeekMax; i++) Parallel.For(0, iSeekMax, i => { ImageLet imgLet = aImgLet[i]; // 3色, 4箇所の二乗誤差を積算 double dist = 0; for (int a = 0; a < DEF.SQR(DEF.FIT_DELTA); a++) { // 2点間距離(大小関係だけに着目するのでroot処理は不要) dist += DEF.SQR(aCol[a].R - imgLet.adAveR[a]) + DEF.SQR(aCol[a].G - imgLet.adAveG[a]) + DEF.SQR(aCol[a].B - imgLet.adAveB[a]); } // 最近距離の更新 if (dist < dstMin) { // 排他処理 lock (thisLock) { iRet = i; dstMin = dist; } } }); dDelta = dstMin; return(iRet); }
// 実処理 public static async Task <ECode> Do(ImgPath path, CoreResult coreResult, IProgress <int> spProg1, IProgress <int> spProg2) { Func <ECode> Job = () => { // ターゲット画像の読み込み Image imgTg = null; try { imgTg = Image.FromFile(path.STgtImg); } catch (Exception) { return(ECode.Er_ReadTgeImg); } Bitmap bmTg = new Bitmap(imgTg); // LetImgの配列を構築 List <ImageLet> aImgLet = MakeImageLets(path.AsSrcImg, spProg1); if (aImgLet.Count < DEF.SQR(DEF.LET_IMG_MIN_MIN)) { return(ECode.Er_LackSrcImg); } // 出力先の構築(取り敢えずオリジナル画像をリサイズして突っ込む) int iCelW, iCelH; CalcCelSize(imgTg, aImgLet, out iCelW, out iCelH); var bmTmp = new Bitmap(bmTg, DEF.LET_D * iCelW, DEF.LET_D * iCelH); var imgOut = new UMImage(bmTmp); bmTmp.Dispose(); // ターゲット画像Celの配列作成 List <ImageCel> aImgCel = MakeImageCels(imgTg, iCelW, iCelH); // 残差計算の処理 double dDeltaSum = 0; double dDeltaMax = 0; // モザイク処理 int iProg = 0; foreach (ImageCel imgCel in aImgCel) { int cy = (int)imgCel.pt.Y; int cx = (int)imgCel.pt.X; // 最も近いimgLetを選択 double dDelta = 0; int iSel = SelectImageLet(imgCel.aCol, aImgLet, out dDelta); ImageLet imgLet = aImgLet[iSel]; dDeltaSum += dDelta; dDeltaMax = Math.Max(dDelta, dDeltaMax); //for (int dy = 0; dy < DEF.LET_D; dy++) Parallel.For(0, DEF.LET_D, dy => { int y = cy * DEF.LET_D + dy; for (int dx = 0; dx < DEF.LET_D; dx++) { int x = cx * DEF.LET_D + dx; // 値の取得() imgOut.SetPixel(x, y, CommonUtils.ColorBlend(imgLet.bmData.GetPixel(dx, dy), 1, imgOut.GetPixel(x, y), 0)); } }); // 一度使ったimgLetはもう使わない aImgLet.RemoveAt(iSel); // どこにも属さないimgLetが溜まらないように、適度にシャッフル if (((iProg + 1) % (DEF.SEEK_MAX / 2)) == 0) { aImgCel = new List <ImageCel>(aImgCel.OrderBy(i => Guid.NewGuid()).ToArray()); } // プログレス処理 spProg2.Report((++iProg) * DEF.PERCENT_MAX / (iCelW * iCelH)); } coreResult.dDeltaAve = dDeltaSum / aImgCel.Count; coreResult.dDeltaMax = dDeltaMax; // ファイルを出力して開く using (Bitmap bmOut = imgOut.GetBitmap()) { bmOut.Save(path.SDstImg, System.Drawing.Imaging.ImageFormat.Jpeg); System.Diagnostics.Process.Start(path.SDstImg); } // お片付け imgTg.Dispose(); bmTg.Dispose(); return(ECode.Success); }; return(await Task.Run(Job)); }
public ImageLet() { adAveR = new double[DEF.SQR(DEF.FIT_DELTA)]; adAveG = new double[DEF.SQR(DEF.FIT_DELTA)]; adAveB = new double[DEF.SQR(DEF.FIT_DELTA)]; }
public Color[] aCol; // FIT_DELTA*FIT_DELTA個 public ImageCel() { aCol = new Color[DEF.SQR(DEF.FIT_DELTA)]; }