আমি পড়া ছিল রঙ স্পেস এবং ল্যাব স্থান একটি ভালো বিকল্প হতে আপনার জন্য প্রদর্শিত হবে (এই প্রশ্ন দেখুন: রং মধ্যে একটি সঠিক "দূরত্ব" খোঁজা এবং অ্যালগরিদম রঙের সাদৃশ্য চেক করতে )
উইকিপিডিয়া সিআইএলএবি পৃষ্ঠার উদ্ধৃতি দিয়ে , এই রঙের স্থানের সুবিধাগুলি হ'ল :
আরজিবি এবং সিএমওয়াইকে রঙের মডেলগুলির বিপরীতে ল্যাব রঙটি প্রায় মানুষের দৃষ্টিভঙ্গির জন্য ডিজাইন করা হয়েছে। এটি অনুধাবনযোগ্য অভিন্নতা অর্জনের উচ্চাকাঙ্ক্ষী এবং এর এল উপাদানটি স্বাচ্ছন্দ্যের সাথে মানুষের ধারণার সাথে ঘনিষ্ঠভাবে মেলে। সুতরাং, এ এবং বি উপাদানগুলিতে আউটপুট বক্ররেখা সংশোধন করে সঠিক রঙের ভারসাম্য সংশোধন করতে এটি ব্যবহার করা যেতে পারে।
রঙগুলির মধ্যে দূরত্ব পরিমাপ করতে আপনি ডেল্টা ই দূরত্ব ব্যবহার করতে পারেন ।
এই আপনি থেকে ভাল অনুমান করতে পারে Color
থেকে ConsoleColor
:
প্রথমত, আপনি CieLab
এই স্থানটিতে রঙ উপস্থাপন করতে কোনও শ্রেণি সংজ্ঞায়িত করতে পারেন :
public class CieLab
{
public double L { get; set; }
public double A { get; set; }
public double B { get; set; }
public static double DeltaE(CieLab l1, CieLab l2)
{
return Math.Pow(l1.L - l2.L, 2) + Math.Pow(l1.A - l2.A, 2) + Math.Pow(l1.B - l2.B, 2);
}
public static CieLab Combine(CieLab l1, CieLab l2, double amount)
{
var l = l1.L * amount + l2.L * (1 - amount);
var a = l1.A * amount + l2.A * (1 - amount);
var b = l1.B * amount + l2.B * (1 - amount);
return new CieLab { L = l, A = a, B = b };
}
}
দুটি স্থিতিশীল পদ্ধতি রয়েছে, একটি হ'ল ডেল্টা ই ( DeltaE
) ব্যবহার করে দূরত্ব পরিমাপ করার জন্য এবং অন্যটি দুটি রঙের সংমিশ্রণে প্রতিটি রঙের কত পরিমাণ নির্দিষ্ট করে ( Combine
)।
আর থেকে রুপান্তর জন্য RGB
করতে LAB
আপনি নিম্নলিখিত পদ্ধতি (থেকে ব্যবহার করতে পারেন এখানে ):
public static CieLab RGBtoLab(int red, int green, int blue)
{
var rLinear = red / 255.0;
var gLinear = green / 255.0;
var bLinear = blue / 255.0;
double r = rLinear > 0.04045 ? Math.Pow((rLinear + 0.055) / (1 + 0.055), 2.2) : (rLinear / 12.92);
double g = gLinear > 0.04045 ? Math.Pow((gLinear + 0.055) / (1 + 0.055), 2.2) : (gLinear / 12.92);
double b = bLinear > 0.04045 ? Math.Pow((bLinear + 0.055) / (1 + 0.055), 2.2) : (bLinear / 12.92);
var x = r * 0.4124 + g * 0.3576 + b * 0.1805;
var y = r * 0.2126 + g * 0.7152 + b * 0.0722;
var z = r * 0.0193 + g * 0.1192 + b * 0.9505;
Func<double, double> Fxyz = t => ((t > 0.008856) ? Math.Pow(t, (1.0 / 3.0)) : (7.787 * t + 16.0 / 116.0));
return new CieLab
{
L = 116.0 * Fxyz(y / 1.0) - 16,
A = 500.0 * (Fxyz(x / 0.9505) - Fxyz(y / 1.0)),
B = 200.0 * (Fxyz(y / 1.0) - Fxyz(z / 1.0890))
};
}
ধারণাটি হ'ল @ অ্যান্টোনিনলেজেক ডু ('█', '▓', '▒', '░') এর মতো ছায়াযুক্ত অক্ষর ব্যবহার করুন, এটি আপনাকে কনসোল রঙগুলির সমন্বয় ( Combine
পদ্ধতি ব্যবহার করে ) 16 টিরও বেশি রঙ পেতে দেয় ।
এখানে, রঙগুলি ব্যবহার করার জন্য প্রাক-গণনা করে আমরা কিছু উন্নতি করতে পারি:
class ConsolePixel
{
public char Char { get; set; }
public ConsoleColor Forecolor { get; set; }
public ConsoleColor Backcolor { get; set; }
public CieLab Lab { get; set; }
}
static List<ConsolePixel> pixels;
private static void ComputeColors()
{
pixels = new List<ConsolePixel>();
char[] chars = { '█', '▓', '▒', '░' };
int[] rs = { 0, 0, 0, 0, 128, 128, 128, 192, 128, 0, 0, 0, 255, 255, 255, 255 };
int[] gs = { 0, 0, 128, 128, 0, 0, 128, 192, 128, 0, 255, 255, 0, 0, 255, 255 };
int[] bs = { 0, 128, 0, 128, 0, 128, 0, 192, 128, 255, 0, 255, 0, 255, 0, 255 };
for (int i = 0; i < 16; i++)
for (int j = i + 1; j < 16; j++)
{
var l1 = RGBtoLab(rs[i], gs[i], bs[i]);
var l2 = RGBtoLab(rs[j], gs[j], bs[j]);
for (int k = 0; k < 4; k++)
{
var l = CieLab.Combine(l1, l2, (4 - k) / 4.0);
pixels.Add(new ConsolePixel
{
Char = chars[k],
Forecolor = (ConsoleColor)i,
Backcolor = (ConsoleColor)j,
Lab = l
});
}
}
}
আর একটি উন্নতি ব্যবহারের LockBits
পরিবর্তে চিত্রের ডেটাতে সরাসরি অ্যাক্সেস হতে পারে GetPixel
।
আপডেট : চিত্রটিতে একই রঙের অংশ থাকলে আপনি পৃথক অক্ষরের পরিবর্তে একই বর্ণযুক্ত অক্ষরের অঙ্কন প্রক্রিয়াটি যথেষ্ট গতিতে করতে পারেন:
public static void DrawImage(Bitmap source)
{
int width = Console.WindowWidth - 1;
int height = (int)(width * source.Height / 2.0 / source.Width);
using (var bmp = new Bitmap(source, width, height))
{
var unit = GraphicsUnit.Pixel;
using (var src = bmp.Clone(bmp.GetBounds(ref unit), PixelFormat.Format24bppRgb))
{
var bits = src.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, src.PixelFormat);
byte[] data = new byte[bits.Stride * bits.Height];
Marshal.Copy(bits.Scan0, data, 0, data.Length);
for (int j = 0; j < height; j++)
{
StringBuilder builder = new StringBuilder();
var fore = ConsoleColor.White;
var back = ConsoleColor.Black;
for (int i = 0; i < width; i++)
{
int idx = j * bits.Stride + i * 3;
var pixel = DrawPixel(data[idx + 2], data[idx + 1], data[idx + 0]);
if (pixel.Forecolor != fore || pixel.Backcolor != back)
{
Console.ForegroundColor = fore;
Console.BackgroundColor = back;
Console.Write(builder);
builder.Clear();
}
fore = pixel.Forecolor;
back = pixel.Backcolor;
builder.Append(pixel.Char);
}
Console.ForegroundColor = fore;
Console.BackgroundColor = back;
Console.WriteLine(builder);
}
Console.ResetColor();
}
}
}
private static ConsolePixel DrawPixel(int r, int g, int b)
{
var l = RGBtoLab(r, g, b);
double diff = double.MaxValue;
var pixel = pixels[0];
foreach (var item in pixels)
{
var delta = CieLab.DeltaE(l, item.Lab);
if (delta < diff)
{
diff = delta;
pixel = item;
}
}
return pixel;
}
অবশেষে, এর DrawImage
মতো কল করুন :
static void Main(string[] args)
{
ComputeColors();
Bitmap image = new Bitmap("image.jpg", true);
DrawImage(image);
}
ফলাফল চিত্রসমূহ:
নিম্নলিখিত সমাধানগুলি অক্ষরের উপর ভিত্তি করে নয় তবে সম্পূর্ণ বিশদ চিত্র সরবরাহ করে
কোনও বস্তু তৈরি করতে আপনি কোনও উইন্ডোটির হ্যান্ডলারটি ব্যবহার করে আঁকতে পারেন Graphics
। কনসোল অ্যাপ্লিকেশনটির হ্যান্ডলারটি পেতে আপনি এটি আমদানি করতে পারেন GetConsoleWindow
:
[DllImport("kernel32.dll", EntryPoint = "GetConsoleWindow", SetLastError = true)]
private static extern IntPtr GetConsoleHandle();
তারপরে, হ্যান্ডলারের সাহায্যে একটি গ্রাফিক তৈরি করুন (ব্যবহার করে Graphics.FromHwnd
) এবং Graphics
অবজেক্টের পদ্ধতি ব্যবহার করে চিত্রটি আঁকুন , উদাহরণস্বরূপ:
static void Main(string[] args)
{
var handler = GetConsoleHandle();
using (var graphics = Graphics.FromHwnd(handler))
using (var image = Image.FromFile("img101.png"))
graphics.DrawImage(image, 50, 50, 250, 200);
}
এটি দুর্দান্ত দেখায় তবে কনসোলটির আকার পরিবর্তন বা স্ক্রোল করা থাকলে উইন্ডোজ সতেজ হওয়ার কারণে চিত্রটি অদৃশ্য হয়ে যায় (সম্ভবত আপনার ক্ষেত্রে চিত্র পুনর্নির্মাণের জন্য কোনও ধরণের প্রক্রিয়া প্রয়োগ করা সম্ভব))
অন্য সমাধানটি Form
কনসোল অ্যাপ্লিকেশনটিতে একটি উইন্ডো ( ) এম্বেড করা। এটি করতে আপনাকে আমদানি করতে হবে SetParent
(এবং MoveWindow
কনসোলের ভিতরে উইন্ডোটি স্থানান্তর করতে হবে):
[DllImport("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
তারপরে আপনাকে কেবল একটি তৈরি করতে এবং পছন্দসই চিত্রটিতে সম্পত্তি Form
সেট BackgroundImage
করতে হবে (এটি একটিতে করুন Thread
বা Task
কনসোলটি ব্লক করা এড়াতে):
static void Main(string[] args)
{
Task.Factory.StartNew(ShowImage);
Console.ReadLine();
}
static void ShowImage()
{
var form = new Form
{
BackgroundImage = Image.FromFile("img101.png"),
BackgroundImageLayout = ImageLayout.Stretch
};
var parent = GetConsoleHandle();
var child = form.Handle;
SetParent(child, parent);
MoveWindow(child, 50, 50, 250, 200, true);
Application.Run(form);
}
অবশ্যই আপনি FormBorderStyle = FormBorderStyle.None
উইন্ডোস বর্ডারগুলি লুকানোর জন্য সেট করতে পারেন (ডান চিত্র)
এই ক্ষেত্রে আপনি কনসোলটির আকার পরিবর্তন করতে পারেন এবং চিত্র / উইন্ডোটি এখনও সেখানে থাকবে।
এই পদ্ধতির সাথে একটি সুবিধা হ'ল আপনি যে উইন্ডোটি চান তা সন্ধান করতে পারেন এবং যে কোনও সময়ে কেবল BackgroundImage
সম্পত্তি পরিবর্তন করে চিত্রটি পরিবর্তন করতে পারেন ।