Jam*_*uth 5 c# graphics imageprocessor
我问这个问题是因为另一个问题已经两年了并且没有准确回答。
我希望用 C#复制本文中提到的 PhotoShop 效果。Adobe 称它为彩色半色调,我认为它看起来像是某种旋转的 CMYK 半色调。无论哪种方式,我都不知道我会怎么做。
当前代码示例如下。
有任何想法吗?

聚苯乙烯
这不是家庭作业。我希望升级我的 OSS 项目ImageProcessor 中的漫画书效果。

所以这里有一些代码来显示我到目前为止所做的......
我可以相当容易和准确地在 CMYK 和 RGB 之间进行转换,足以满足我的需要,并且还可以根据一系列点的每个颜色分量的强度打印出一系列有图案的椭圆。
我刚才遇到的是旋转每种颜色的图形对象,以便将点放置在代码中指定的角度。任何人都可以给我一些关于如何去做的指示吗?
public Image ProcessImage(ImageFactory factory)
{
Bitmap newImage = null;
Image image = factory.Image;
try
{
int width = image.Width;
int height = image.Height;
// These need to be used.
float cyanAngle = 105f;
float magentaAngle = 75f;
float yellowAngle = 90f;
float keylineAngle = 15f;
newImage = new Bitmap(width, height);
newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (Graphics graphics = Graphics.FromImage(newImage))
{
// Reduce the jagged edges.
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.Clear(Color.White);
using (FastBitmap sourceBitmap = new FastBitmap(image))
{
for (int y = 0; y < height; y += 4)
{
for (int x = 0; x < width; x += 4)
{
Color color = sourceBitmap.GetPixel(x, y);
if (color != Color.White)
{
CmykColor cmykColor = color;
float cyanBrushRadius = (cmykColor.C / 100) * 3;
graphics.FillEllipse(Brushes.Cyan, x, y, cyanBrushRadius, cyanBrushRadius);
float magentaBrushRadius = (cmykColor.M / 100) * 3;
graphics.FillEllipse(Brushes.Magenta, x, y, magentaBrushRadius, magentaBrushRadius);
float yellowBrushRadius = (cmykColor.Y / 100) * 3;
graphics.FillEllipse(Brushes.Yellow, x, y, yellowBrushRadius, yellowBrushRadius);
float blackBrushRadius = (cmykColor.K / 100) * 3;
graphics.FillEllipse(Brushes.Black, x, y, blackBrushRadius, blackBrushRadius);
}
}
}
}
}
image.Dispose();
image = newImage;
}
catch (Exception ex)
{
if (newImage != null)
{
newImage.Dispose();
}
throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex);
}
return image;
}
Run Code Online (Sandbox Code Playgroud)
输入图像

正如您所看到的,由于绘制的椭圆没有倾斜,因此颜色输出不正确。

这是一个可行的解决方案。它并不漂亮,也不快(在我的笔记本电脑上为 2 秒),但输出很好。尽管我认为他们正在执行一些额外的工作,但它与 Photoshop 的输出并不完全匹配。
\n\n轻微的摩尔纹\xc3\xa9 图案有时会出现在不同的测试图像上,但去网纹超出了当前问题的范围。
\n\n该代码执行以下步骤。
\n\n输出图像
\n\n
代码\n
\n\npublic Image ProcessImage(ImageFactory factory)\n{\n Bitmap cyan = null;\n Bitmap magenta = null;\n Bitmap yellow = null;\n Bitmap keyline = null;\n Bitmap newImage = null;\n Image image = factory.Image;\n\n try\n {\n int width = image.Width;\n int height = image.Height;\n\n // Angles taken from Wikipedia page.\n float cyanAngle = 15f;\n float magentaAngle = 75f;\n float yellowAngle = 0f;\n float keylineAngle = 45f;\n\n int diameter = 4;\n float multiplier = 4 * (float)Math.Sqrt(2);\n\n // Cyan color sampled from Wikipedia page.\n Brush cyanBrush = new SolidBrush(Color.FromArgb(0, 153, 239));\n Brush magentaBrush = Brushes.Magenta;\n Brush yellowBrush = Brushes.Yellow;\n Brush keylineBrush;\n\n // Create our images.\n cyan = new Bitmap(width, height);\n magenta = new Bitmap(width, height);\n yellow = new Bitmap(width, height);\n keyline = new Bitmap(width, height);\n newImage = new Bitmap(width, height);\n\n // Ensure the correct resolution is set.\n cyan.SetResolution(image.HorizontalResolution, image.VerticalResolution);\n magenta.SetResolution(image.HorizontalResolution, image.VerticalResolution);\n yellow.SetResolution(image.HorizontalResolution, image.VerticalResolution);\n keyline.SetResolution(image.HorizontalResolution, image.VerticalResolution);\n newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);\n\n // Check bounds against this.\n Rectangle rectangle = new Rectangle(0, 0, width, height);\n\n using (Graphics graphicsCyan = Graphics.FromImage(cyan))\n using (Graphics graphicsMagenta = Graphics.FromImage(magenta))\n using (Graphics graphicsYellow = Graphics.FromImage(yellow))\n using (Graphics graphicsKeyline = Graphics.FromImage(keyline))\n {\n // Ensure cleared out.\n graphicsCyan.Clear(Color.Transparent);\n graphicsMagenta.Clear(Color.Transparent);\n graphicsYellow.Clear(Color.Transparent);\n graphicsKeyline.Clear(Color.Transparent);\n\n // This is too slow. The graphics object can\'t be called within a parallel \n // loop so we have to do it old school. :(\n using (FastBitmap sourceBitmap = new FastBitmap(image))\n {\n for (int y = -height * 2; y < height * 2; y += diameter)\n {\n for (int x = -width * 2; x < width * 2; x += diameter)\n {\n Color color;\n CmykColor cmykColor;\n float brushWidth;\n\n // Cyan\n Point rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), cyanAngle);\n int angledX = rotatedPoint.X;\n int angledY = rotatedPoint.Y;\n if (rectangle.Contains(new Point(angledX, angledY)))\n {\n color = sourceBitmap.GetPixel(angledX, angledY);\n cmykColor = color;\n brushWidth = diameter * (cmykColor.C / 255f) * multiplier;\n graphicsCyan.FillEllipse(cyanBrush, angledX, angledY, brushWidth, brushWidth);\n }\n\n // Magenta\n rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), magentaAngle);\n angledX = rotatedPoint.X;\n angledY = rotatedPoint.Y;\n if (rectangle.Contains(new Point(angledX, angledY)))\n {\n color = sourceBitmap.GetPixel(angledX, angledY);\n cmykColor = color;\n brushWidth = diameter * (cmykColor.M / 255f) * multiplier;\n graphicsMagenta.FillEllipse(magentaBrush, angledX, angledY, brushWidth, brushWidth);\n }\n\n // Yellow\n rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), yellowAngle);\n angledX = rotatedPoint.X;\n angledY = rotatedPoint.Y;\n if (rectangle.Contains(new Point(angledX, angledY)))\n {\n color = sourceBitmap.GetPixel(angledX, angledY);\n cmykColor = color;\n brushWidth = diameter * (cmykColor.Y / 255f) * multiplier;\n graphicsYellow.FillEllipse(yellowBrush, angledX, angledY, brushWidth, brushWidth);\n }\n\n // Keyline \n rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), keylineAngle);\n angledX = rotatedPoint.X;\n angledY = rotatedPoint.Y;\n if (rectangle.Contains(new Point(angledX, angledY)))\n {\n color = sourceBitmap.GetPixel(angledX, angledY);\n cmykColor = color;\n brushWidth = diameter * (cmykColor.K / 255f) * multiplier;\n\n // Just using blck is too dark. \n keylineBrush = new SolidBrush(CmykColor.FromCmykColor(0, 0, 0, cmykColor.K));\n graphicsKeyline.FillEllipse(keylineBrush, angledX, angledY, brushWidth, brushWidth);\n }\n }\n }\n }\n\n // Set our white background.\n using (Graphics graphics = Graphics.FromImage(newImage))\n {\n graphics.Clear(Color.White);\n }\n\n // Blend the colors now to mimic adaptive blending.\n using (FastBitmap cyanBitmap = new FastBitmap(cyan))\n using (FastBitmap magentaBitmap = new FastBitmap(magenta))\n using (FastBitmap yellowBitmap = new FastBitmap(yellow))\n using (FastBitmap keylineBitmap = new FastBitmap(keyline))\n using (FastBitmap destinationBitmap = new FastBitmap(newImage))\n {\n Parallel.For(\n 0,\n height,\n y =>\n {\n for (int x = 0; x < width; x++)\n {\n // ReSharper disable AccessToDisposedClosure\n Color cyanPixel = cyanBitmap.GetPixel(x, y);\n Color magentaPixel = magentaBitmap.GetPixel(x, y);\n Color yellowPixel = yellowBitmap.GetPixel(x, y);\n Color keylinePixel = keylineBitmap.GetPixel(x, y);\n\n CmykColor blended = cyanPixel.AddAsCmykColor(magentaPixel, yellowPixel, keylinePixel);\n destinationBitmap.SetPixel(x, y, blended);\n // ReSharper restore AccessToDisposedClosure\n }\n });\n }\n }\n\n cyan.Dispose();\n magenta.Dispose();\n yellow.Dispose();\n keyline.Dispose();\n image.Dispose();\n image = newImage;\n }\n catch (Exception ex)\n {\n if (cyan != null)\n {\n cyan.Dispose();\n }\n\n if (magenta != null)\n {\n magenta.Dispose();\n }\n\n if (yellow != null)\n {\n yellow.Dispose();\n }\n\n if (keyline != null)\n {\n keyline.Dispose();\n }\n\n if (newImage != null)\n {\n newImage.Dispose();\n }\n\n throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex);\n }\n\n return image;\n} \nRun Code Online (Sandbox Code Playgroud)\n\n用于旋转像素的附加代码如下。这可以在围绕另一个点旋转一个点中找到
\n\n为了简洁起见,我省略了颜色添加代码。
\n\npublic Image ProcessImage(ImageFactory factory)\n{\n Bitmap cyan = null;\n Bitmap magenta = null;\n Bitmap yellow = null;\n Bitmap keyline = null;\n Bitmap newImage = null;\n Image image = factory.Image;\n\n try\n {\n int width = image.Width;\n int height = image.Height;\n\n // Angles taken from Wikipedia page.\n float cyanAngle = 15f;\n float magentaAngle = 75f;\n float yellowAngle = 0f;\n float keylineAngle = 45f;\n\n int diameter = 4;\n float multiplier = 4 * (float)Math.Sqrt(2);\n\n // Cyan color sampled from Wikipedia page.\n Brush cyanBrush = new SolidBrush(Color.FromArgb(0, 153, 239));\n Brush magentaBrush = Brushes.Magenta;\n Brush yellowBrush = Brushes.Yellow;\n Brush keylineBrush;\n\n // Create our images.\n cyan = new Bitmap(width, height);\n magenta = new Bitmap(width, height);\n yellow = new Bitmap(width, height);\n keyline = new Bitmap(width, height);\n newImage = new Bitmap(width, height);\n\n // Ensure the correct resolution is set.\n cyan.SetResolution(image.HorizontalResolution, image.VerticalResolution);\n magenta.SetResolution(image.HorizontalResolution, image.VerticalResolution);\n yellow.SetResolution(image.HorizontalResolution, image.VerticalResolution);\n keyline.SetResolution(image.HorizontalResolution, image.VerticalResolution);\n newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);\n\n // Check bounds against this.\n Rectangle rectangle = new Rectangle(0, 0, width, height);\n\n using (Graphics graphicsCyan = Graphics.FromImage(cyan))\n using (Graphics graphicsMagenta = Graphics.FromImage(magenta))\n using (Graphics graphicsYellow = Graphics.FromImage(yellow))\n using (Graphics graphicsKeyline = Graphics.FromImage(keyline))\n {\n // Ensure cleared out.\n graphicsCyan.Clear(Color.Transparent);\n graphicsMagenta.Clear(Color.Transparent);\n graphicsYellow.Clear(Color.Transparent);\n graphicsKeyline.Clear(Color.Transparent);\n\n // This is too slow. The graphics object can\'t be called within a parallel \n // loop so we have to do it old school. :(\n using (FastBitmap sourceBitmap = new FastBitmap(image))\n {\n for (int y = -height * 2; y < height * 2; y += diameter)\n {\n for (int x = -width * 2; x < width * 2; x += diameter)\n {\n Color color;\n CmykColor cmykColor;\n float brushWidth;\n\n // Cyan\n Point rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), cyanAngle);\n int angledX = rotatedPoint.X;\n int angledY = rotatedPoint.Y;\n if (rectangle.Contains(new Point(angledX, angledY)))\n {\n color = sourceBitmap.GetPixel(angledX, angledY);\n cmykColor = color;\n brushWidth = diameter * (cmykColor.C / 255f) * multiplier;\n graphicsCyan.FillEllipse(cyanBrush, angledX, angledY, brushWidth, brushWidth);\n }\n\n // Magenta\n rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), magentaAngle);\n angledX = rotatedPoint.X;\n angledY = rotatedPoint.Y;\n if (rectangle.Contains(new Point(angledX, angledY)))\n {\n color = sourceBitmap.GetPixel(angledX, angledY);\n cmykColor = color;\n brushWidth = diameter * (cmykColor.M / 255f) * multiplier;\n graphicsMagenta.FillEllipse(magentaBrush, angledX, angledY, brushWidth, brushWidth);\n }\n\n // Yellow\n rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), yellowAngle);\n angledX = rotatedPoint.X;\n angledY = rotatedPoint.Y;\n if (rectangle.Contains(new Point(angledX, angledY)))\n {\n color = sourceBitmap.GetPixel(angledX, angledY);\n cmykColor = color;\n brushWidth = diameter * (cmykColor.Y / 255f) * multiplier;\n graphicsYellow.FillEllipse(yellowBrush, angledX, angledY, brushWidth, brushWidth);\n }\n\n // Keyline \n rotatedPoint = RotatePoint(new Point(x, y), new Point(0, 0), keylineAngle);\n angledX = rotatedPoint.X;\n angledY = rotatedPoint.Y;\n if (rectangle.Contains(new Point(angledX, angledY)))\n {\n color = sourceBitmap.GetPixel(angledX, angledY);\n cmykColor = color;\n brushWidth = diameter * (cmykColor.K / 255f) * multiplier;\n\n // Just using blck is too dark. \n keylineBrush = new SolidBrush(CmykColor.FromCmykColor(0, 0, 0, cmykColor.K));\n graphicsKeyline.FillEllipse(keylineBrush, angledX, angledY, brushWidth, brushWidth);\n }\n }\n }\n }\n\n // Set our white background.\n using (Graphics graphics = Graphics.FromImage(newImage))\n {\n graphics.Clear(Color.White);\n }\n\n // Blend the colors now to mimic adaptive blending.\n using (FastBitmap cyanBitmap = new FastBitmap(cyan))\n using (FastBitmap magentaBitmap = new FastBitmap(magenta))\n using (FastBitmap yellowBitmap = new FastBitmap(yellow))\n using (FastBitmap keylineBitmap = new FastBitmap(keyline))\n using (FastBitmap destinationBitmap = new FastBitmap(newImage))\n {\n Parallel.For(\n 0,\n height,\n y =>\n {\n for (int x = 0; x < width; x++)\n {\n // ReSharper disable AccessToDisposedClosure\n Color cyanPixel = cyanBitmap.GetPixel(x, y);\n Color magentaPixel = magentaBitmap.GetPixel(x, y);\n Color yellowPixel = yellowBitmap.GetPixel(x, y);\n Color keylinePixel = keylineBitmap.GetPixel(x, y);\n\n CmykColor blended = cyanPixel.AddAsCmykColor(magentaPixel, yellowPixel, keylinePixel);\n destinationBitmap.SetPixel(x, y, blended);\n // ReSharper restore AccessToDisposedClosure\n }\n });\n }\n }\n\n cyan.Dispose();\n magenta.Dispose();\n yellow.Dispose();\n keyline.Dispose();\n image.Dispose();\n image = newImage;\n }\n catch (Exception ex)\n {\n if (cyan != null)\n {\n cyan.Dispose();\n }\n\n if (magenta != null)\n {\n magenta.Dispose();\n }\n\n if (yellow != null)\n {\n yellow.Dispose();\n }\n\n if (keyline != null)\n {\n keyline.Dispose();\n }\n\n if (newImage != null)\n {\n newImage.Dispose();\n }\n\n throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex);\n }\n\n return image;\n} \nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
768 次 |
| 最近记录: |