[英]How do I rotate hue in a picturebox image?
首先,我要花4个小时探讨这个问题的各种变化。 大多数答案参考MSDN上的教程,这些教程涉及获取颜色块并绘制具有不同色调的新矩形。 这与我要执行的操作完全不同。 我想在图片框中拍摄图像,然后旋转整个图像的色相(从1到359度之间的任何位置)。
这个问题完美地展示了我想做的事情: 使用C#旋转Hue 。 不幸的是,答案参考的是C / C ++,而不是C#。 这是第一个,我没有代码可发布,因为没有什么事情可以完成我想要完成的工作。 谢谢。
编辑:我只是在使用一些我认为未成功的代码,结果是我的结果只是隐藏的,正在进行一些色相更改,而且很快,只是不正确。 到目前为止,这是我所拥有的:
private void ColorRotation_Click(object sender, EventArgs e)
{
if (pictureBoxMain.Image != null)
{
Bitmap image = new Bitmap(pictureBoxMain.Image);
ImageAttributes imageAttributes = new ImageAttributes();
int width = image.Width;
int height = image.Height;
float degrees = 60f;
double r = degrees * System.Math.PI / 180; // degrees to radians
float[][] colorMatrixElements = {
new float[] {(float)System.Math.Cos(r), (float)System.Math.Sin(r), 0, 0, 0},
new float[] {(float)-System.Math.Sin(r), (float)-System.Math.Cos(r), 0, 0, 0},
new float[] {0, 0, 2, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}};
ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);
imageAttributes.SetColorMatrix(
colorMatrix,
ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
Graphics myGraphics = CreateGraphics();
Rectangle myRectangle = new Rectangle();
pictureBoxMain.Image = image;
myRectangle.Width = pictureBoxMain.Width;
myRectangle.Height = pictureBoxMain.Height;
myGraphics.DrawImage(pictureBoxMain.Image, myRectangle, 30, 50, myRectangle.Width, myRectangle.Height, GraphicsUnit.Pixel, imageAttributes);
pictureBoxMain.Refresh();
}
}
这里有两个问题:
我以为“浮动度= 60f;” 会给我60度的旋转角度,结果我得到大约180度的旋转角度。 如何纠正这个问题,以便获得正确的色相旋转量? 我期望60度并获得180度是一个巨大的错误。
结果不会作为新图像添加到pictureBox中。 它在窗体上被绘制为矩形。 我找不到“ myGraphics.DrawImage()”的重载(我尝试了全部30个),该重载接受pictureBox以及所需的“ GraphicsUnit.Pixel”和“ imageAttributes”。 如何更新此代码,以便对图片框中的图像进行更改而不是在表单上绘制? 也许myGraphics.DrawImage()不是答案。
非常感谢
基于此处提供的RGB转换方案,此代码将对HueRotatePictureBox
控件中的图像执行HueRotateAngleSelector.Value
度的色相旋转:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows.Forms;
...
private void HueRotateButton_Click(object sender, EventArgs e)
{
// Get the cosine and sine of the selected hue rotation angle
var radians = Math.PI * (double)HueRotateAngleSelector.Value / 180.0;
var cos = Math.Cos(radians);
var sin = Math.Sin(radians);
// Calculate the elements of the RGB transformation matrix
var a00 = 0.213 + cos * 0.787 - sin * 0.213;
var a01 = 0.213 - cos * 0.213 + sin * 0.143;
var a02 = 0.213 - cos * 0.213 - sin * 0.787;
var a10 = 0.715 - cos * 0.715 - sin * 0.715;
var a11 = 0.715 + cos * 0.285 + sin * 0.140;
var a12 = 0.715 - cos * 0.715 + sin * 0.715;
var a20 = 0.072 - cos * 0.072 + sin * 0.928;
var a21 = 0.072 - cos * 0.072 - sin * 0.283;
var a22 = 0.072 + cos * 0.928 + sin * 0.072;
// Get the current image from the picture box control, ...
var bitmap = (Bitmap)HueRotatePictureBox.Image;
var width = bitmap.Width;
var height = bitmap.Height;
// ... and open it for modification
var bitmapData = bitmap.LockBits(
new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb);
var scan0 = bitmapData.Scan0;
var stride = bitmapData.Stride;
// Copy the image pixels to a local byte array
var length = height * stride;
var bytes = new byte[length];
Marshal.Copy(scan0, bytes, 0, length);
// Loop over all pixels in the image
for (var y = 0; y < height; y++)
{
var offset = stride * y;
for (var x = 0; x < width; x++, offset += 4)
{
// Get the original RGB components for the individual pixel
// (the alpha component should not be changed and is therefore ignored)
double b = bytes[offset];
double g = bytes[offset + 1];
double r = bytes[offset + 2];
// Apply the hue rotation transform
var rr = Math.Max(0.0, Math.Min(255.0, r * a00 + g * a10 + b * a20));
var gr = Math.Max(0.0, Math.Min(255.0, r * a01 + g * a11 + b * a21));
var br = Math.Max(0.0, Math.Min(255.0, r * a02 + g * a12 + b * a22));
// Update the RGB components
bytes[offset] = (byte)br;
bytes[offset + 1] = (byte)gr;
bytes[offset + 2] = (byte)rr;
}
}
// Bitmap editing is finished, transfer the updated byte array to the image pixels
// and "lock" the image again
Marshal.Copy(bytes, 0, scan0, length);
bitmap.UnlockBits(bitmapData);
// Update the image in the picture box
HueRotatePictureBox.Image = bitmap;
}
上面的代码将拍摄如下图像:
180度的色相旋转会将其转换为:
注意! 上面的代码始终在图片框控件中获取当前图像并应用色相旋转。 因此,如果两次应用180°色相旋转,您将返回到原始图像。 如果您希望始终对原始图像应用色相旋转,则应更新var bitmap =
定义以始终从单独的位置选择原始图像。
UPDATE
改用Graphics
, ImageAttributes
和ColorMatrix
方法,可以将按钮事件处理程序编写如下:
private void HueRotateButton_Click(object sender, EventArgs e)
{
// Get the cosine and sine of the selected hue rotation angle
var radians = Math.PI * (double)HueRotateAngleSelector.Value / 180.0;
var cos = (float)Math.Cos(radians);
var sin = (float)Math.Sin(radians);
// Create an image attributes object from a hue rotation color matrix
var colorMatrix =
new ColorMatrix(
new[]
{
new[] { 0.213f + cos * 0.787f - sin * 0.213f, 0.213f - cos * 0.213f + sin * 0.143f, 0.213f - cos * 0.213f - sin * 0.787f, 0f, 0f },
new[] { 0.715f - cos * 0.715f - sin * 0.715f, 0.715f + cos * 0.285f + sin * 0.140f, 0.715f - cos * 0.715f + sin * 0.715f, 0f, 0f },
new[] { 0.072f - cos * 0.072f + sin * 0.928f, 0.072f - cos * 0.072f - sin * 0.283f, 0.072f + cos * 0.928f + sin * 0.072f, 0f, 0f },
new[] { 0f, 0f, 0f, 1f, 0f },
new[] { 0f, 0f, 0f, 0f, 1f }
});
var imageAttributes = new ImageAttributes();
imageAttributes.SetColorMatrix(colorMatrix);
// Get the current image from the picture box control
var bitmap = (Bitmap)HueRotatePictureBox.Image;
var width = bitmap.Width;
var height = bitmap.Height;
// Get a graphics object of the bitmap and draw the hue rotation
// transformed image on the bitmap area
var graphics = Graphics.FromImage(bitmap);
graphics.DrawImage(
bitmap,
new Rectangle(0, 0, width, height),
0,
0,
width,
height,
GraphicsUnit.Pixel,
imageAttributes);
// Update the image in the picutre box
HueRotatePictureBox.Image = bitmap;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.