Skip to content

Commit 90c06d9

Browse files
committed
콜라주 모드 버그 수정: 각 K 클러스터별 이미지 제대로 적용되도록 수정
1 parent 1e1fe92 commit 90c06d9

File tree

2 files changed

+176
-1
lines changed

2 files changed

+176
-1
lines changed

pixelColoring/SaveKMeansForm.Designer.cs

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pixelColoring/SaveKMeansForm.cs

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.ComponentModel;
44
using System.Data;
55
using System.Drawing;
6+
using System.Drawing.Drawing2D;
67
using System.Drawing.Imaging;
78
using System.Linq;
89
using System.Runtime.InteropServices;
@@ -58,6 +59,12 @@ enum Direction
5859
};
5960
Dictionary<int, char> clusterSymbolMap = new Dictionary<int, char>();
6061

62+
// K값에 따라 다른 이미지 로딩
63+
private Dictionary<int, Bitmap> kToImageMap = null;
64+
65+
// 기존 저장 모드
66+
private string previousMode = null;
67+
6168
int cnt = 0;
6269
double avgxx = 0, avgyy = 0, avgdd1 = 0, avgdd2 = 0;
6370

@@ -87,8 +94,21 @@ public SaveKMeansForm(Bitmap original, Bitmap pixelated, int pixelSize,
8794
}
8895
private void cmbSaveForm_SelectedIndexChanged(object sender, EventArgs e)
8996
{
97+
string currentMode = cmbSaveForm.SelectedItem?.ToString();
98+
99+
// "콜라주 사진 만들기"가 선택됐고, 이전 모드가 다른 경우 → 이미지 다시 고르게 만듦
100+
if (currentMode == "콜라주 사진 만들기" && previousMode != "콜라주 사진 만들기")
101+
{
102+
kToImageMap = null; // 이전 모드에서 돌아온 경우이므로 새로 불러오기 허용
103+
}
104+
105+
if (currentMode == previousMode)
106+
return;
107+
108+
previousMode = currentMode;
90109
UpdatePreview();
91110
}
111+
92112
private void UpdatePreview()
93113
{
94114
string mode = cmbSaveForm.SelectedItem?.ToString();
@@ -216,6 +236,115 @@ private void UpdatePreview()
216236
picSavePreview.Image = resizedImage;
217237
picSavePreview.Invalidate();
218238
}
239+
else if (mode == "콜라주 사진 만들기")
240+
{
241+
if (numberGrid == null || pixelColors == null)
242+
{
243+
MessageBox.Show("먼저 픽셀화를 진행하세요.");
244+
return;
245+
}
246+
247+
int width = originalImage.Width;
248+
int height = originalImage.Height;
249+
int cellSize = pixelSize;
250+
251+
// 사용자로부터 이미지 선택 (1회만)
252+
if (kToImageMap == null)
253+
{
254+
kToImageMap = new Dictionary<int, Bitmap>();
255+
for (int i = 1; i <= k; i++)
256+
{
257+
using (OpenFileDialog ofd = new OpenFileDialog())
258+
{
259+
ofd.Title = $"K = {i}에 사용할 이미지를 선택하세요";
260+
ofd.Filter = "이미지 파일 (*.png;*.jpg;*.jpeg;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp";
261+
262+
if (ofd.ShowDialog() == DialogResult.OK)
263+
kToImageMap[i] = new Bitmap(ofd.FileName);
264+
else
265+
{
266+
Bitmap blank = new Bitmap(width, height);
267+
using (Graphics g = Graphics.FromImage(blank)) g.Clear(Color.White);
268+
kToImageMap[i] = blank;
269+
}
270+
}
271+
}
272+
}
273+
274+
// 1. K별 평균 색 계산
275+
Dictionary<int, List<Color>> kColorSamples = new Dictionary<int, List<Color>>();
276+
for (int y = 0; y < numberGrid.GetLength(0); y++)
277+
{
278+
for (int x = 0; x < numberGrid.GetLength(1); x++)
279+
{
280+
Point pt = new Point(x, y);
281+
if (!pixelColors.ContainsKey(pt)) continue;
282+
283+
int kVal = numberGrid[y, x];
284+
if (!kColorSamples.ContainsKey(kVal)) kColorSamples[kVal] = new List<Color>();
285+
kColorSamples[kVal].Add(pixelColors[pt]);
286+
}
287+
}
288+
289+
Dictionary<int, Color> kTargetColor = new Dictionary<int, Color>();
290+
foreach (var kv in kColorSamples)
291+
{
292+
int kr = 0, kg = 0, kb = 0;
293+
foreach (var c in kv.Value)
294+
{
295+
kr += c.R; kg += c.G; kb += c.B;
296+
}
297+
int count = kv.Value.Count;
298+
kTargetColor[kv.Key] = Color.FromArgb(kr / count, kg / count, kb / count);
299+
}
300+
301+
// 2. 각 K 이미지 보정 + 리사이즈
302+
Dictionary<int, Bitmap> resizedKImage = new Dictionary<int, Bitmap>();
303+
foreach (var pair in kToImageMap)
304+
{
305+
int clusterId = pair.Key;
306+
Color target = kTargetColor.ContainsKey(clusterId) ? kTargetColor[clusterId] : Color.Gray;
307+
308+
309+
Bitmap adjusted = TintGrayscaleImage(kToImageMap[clusterId], target);
310+
311+
Bitmap resized = new Bitmap(width, height);
312+
using (Graphics g = Graphics.FromImage(resized))
313+
{
314+
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
315+
g.DrawImage(adjusted, 0, 0, width, height);
316+
}
317+
adjusted.Dispose();
318+
resizedKImage[clusterId] = resized;
319+
}
320+
321+
// 3. 콜라주 구성
322+
resizedImage = new Bitmap(width, height);
323+
for (int y = 0; y < height; y++)
324+
{
325+
for (int x = 0; x < width; x++)
326+
{
327+
int gx = x / cellSize;
328+
int gy = y / cellSize;
329+
330+
if (gx < 0 || gx >= numberGrid.GetLength(1) || gy < 0 || gy >= numberGrid.GetLength(0)) continue;
331+
332+
int kCluster = numberGrid[gy, gx];
333+
if (resizedKImage.ContainsKey(kCluster))
334+
{
335+
Color c = resizedKImage[kCluster].GetPixel(x, y);
336+
resizedImage.SetPixel(x, y, c);
337+
}
338+
}
339+
}
340+
341+
picSavePreview.Image = resizedImage;
342+
picSavePreview.Invalidate();
343+
}
344+
345+
346+
347+
219348
}
220349

221350
private void btnImgSave_Click(object sender, EventArgs e)
@@ -394,6 +523,51 @@ private Dictionary<int, char> GenerateRandomSymbolMap(int k)
394523
return gray;
395524
}
396525

526+
// 이미지와 목표 색상을 매개변수로 한 다음 비트맵으로 반환
527+
public static Bitmap TintGrayscaleImage(Bitmap input, Color tintColor)
528+
{
529+
int width = input.Width;
530+
int height = input.Height;
531+
532+
Bitmap result = new Bitmap(width, height, PixelFormat.Format24bppRgb);
533+
Rectangle rect = new Rectangle(0, 0, width, height);
534+
535+
BitmapData data = input.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
536+
BitmapData outputData = result.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
537+
538+
int stride = data.Stride;
539+
byte[] buffer = new byte[stride * height];
540+
byte[] outBuffer = new byte[stride * height];
541+
542+
Marshal.Copy(data.Scan0, buffer, 0, buffer.Length);
543+
input.UnlockBits(data);
544+
545+
for (int y = 0; y < height; y++)
546+
{
547+
int row = y * stride;
548+
for (int x = 0; x < width; x++)
549+
{
550+
int idx = row + x * 3;
551+
byte b = buffer[idx];
552+
byte g = buffer[idx + 1];
553+
byte r = buffer[idx + 2];
554+
555+
// 회색조 밝기 (가중 평균)
556+
int gray = (int)(r * 0.3 + g * 0.59 + b * 0.11);
557+
558+
outBuffer[idx + 2] = (byte)Math.Min(255, (gray * tintColor.R) / 255);
559+
outBuffer[idx + 1] = (byte)Math.Min(255, (gray * tintColor.G) / 255);
560+
outBuffer[idx] = (byte)Math.Min(255, (gray * tintColor.B) / 255);
561+
}
562+
}
563+
564+
Marshal.Copy(outBuffer, 0, outputData.Scan0, outBuffer.Length);
565+
result.UnlockBits(outputData);
566+
567+
return result;
568+
}
569+
397570

398571
}
399572
}
573+

0 commit comments

Comments
 (0)