我如何可以旋转使用的GDI +图像的色调ImageAttributes
(大概ColorMatrix
)?
请注意,我想旋转色相,不着色的图像。
编辑 :通过旋转色调,我的意思是图像中的每个颜色应该移动到不同的颜色,而不是使整个图像的一种颜色的阴影。
例如,
原文: http://www.codeguru.com/img/legacy/gdi/Tinter03.jpg
旋转: http://www.codeguru.com/img/legacy/gdi/Tinter15.jpg或http://www.codeguru.com/img/legacy/gdi/Tinter17.jpg
Answer 1:
我把这个一起为这个问题(与在文章底部链接C#项目ZIP文件)。 它不使用ImageAttributes
或ColorMatrix
,但它也旋转你所描述的色调:
//rotate hue for a pixel
private Color CalculateHueChange(Color oldColor, float hue)
{
HLSRGB color = new HLSRGB(
Convert.ToByte(oldColor.R),
Convert.ToByte(oldColor.G),
Convert.ToByte(oldColor.B));
float startHue = color.Hue;
color.Hue = startHue + hue;
return color.Color;
}
Answer 2:
我结束了移植QColorMatrix到C#和使用其RotateHue
方法。
Answer 3:
你有没有看到这篇文章在CodeProject上?
从一个公认的快速浏览一下网页,它看起来像4D数学。 您可以采用类似的方法来contstructing矩阵,你会为2D或3D数学。
采取了一系列源“点” - 在这种情况下,你将需要4 - 和相应的目标“点”,并产生一个矩阵。 这可以被应用到任何“点”。
要做到这一点在2D(从内存中,所以我可以做出这个完全吼):
源点是(1,0)和(0,1)。 这些目标是(0,-1)和(1,0)。 你需要的矩阵是:
(0, -1, 0)
(1, 0, 0)
(0, 0, 1)
当额外的信息是坐标的“W”值。
扩展这个多达{R,G,B,A,W},你就会有一个矩阵。 取4种颜色红(1,0,0,0,W),绿(0,1,0,0,W),蓝色(0,0,1,0,w)的和透明的(0,0,0, 1,W)。 制定出它们映射什么颜色在新的方案,并建立你的矩阵如下:
(R 1,G 1,B 1,A 1,0)
(R 2,G 2,B 2,A 2,0)
(R 3,G 3,B 3,A 3,0)
(R 4,G 4,B 4,A 4,0)
(0,0,0,0,1)
注:为了你做你mulitplication(向量*矩阵或矩阵*向量)将决定变换点是否垂直或水平进入这个矩阵,如矩阵乘法是不可交换的。 我假设向量*矩阵。
Answer 4:
这是一个老问题,但发布的解决方案比简单的答案,我发现要复杂得多。
简单:
- 没有外部的依赖
- 没有复杂的计算(没有搞清楚的旋转角度,没有施加一些余弦公式)
- 实际上做的颜色旋转!
再论问题:我们需要什么?
我准备了带有红色图标。 有些地方是透明的,有些是或多或少饱和的,但他们都有红色色调。 我认为你的使用情况非常相称。 这些图像可能有其他的颜色,他们只是旋转。
如何代表色调申请? 最简单的回答是:提供一个Color
。
争取解决工作
ColorMatrix
代表的线性变换。
显然,当颜色为红色,转型应该是身份。 当颜色为绿色,转型应该映射红到绿,绿蓝色,蓝色到红色。
嘉洛斯一个做这个工作:
0 1 0 0 0
0 0 1 0 0
1 0 0 0 0
0 0 0 1 0
0 0 0 0 1
数学解决方案
该“啊哈”关键是要认识到,矩阵的实际形式
R G B 0 0
B R G 0 0
G B R 0 0
0 0 0 1 0
0 0 0 0 1
其中,R,G和B是简单的着色的颜色的分量!
示例代码
我承担了示例代码https://code.msdn.microsoft.com/ColorMatrix-Image-Filters-f6ed20ae 。
我调整了它,并在我的项目实际使用此:
static class IconTinter
{
internal static Bitmap TintedIcon(Image sourceImage, Color tintingColor)
{
// Following https://code.msdn.microsoft.com/ColorMatrix-Image-Filters-f6ed20ae
Bitmap bmp32BppDest = new Bitmap(sourceImage.Width, sourceImage.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
float cr = tintingColor.R / 255.0f;
float cg = tintingColor.G / 255.0f;
float cb = tintingColor.B / 255.0f;
// See [Rotate Hue using ImageAttributes in C#](http://stackoverflow.com/a/26573948/1429390)
ColorMatrix colorMatrix = new ColorMatrix(
new float[][]
{new float[] { cr, cg, cb, 0, 0},
new float[] { cb, cr, cg, 0, 0},
new float[] { cg, cb, cr, 0, 0},
new float[] { 0, 0, 0, 1, 0},
new float[] { 0, 0, 0, 0, 1}
}
);
using (Graphics graphics = Graphics.FromImage(bmp32BppDest))
{
ImageAttributes bmpAttributes = new ImageAttributes();
bmpAttributes.SetColorMatrix(colorMatrix);
graphics.DrawImage(sourceImage,
new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
0, 0,
sourceImage.Width, sourceImage.Height,
GraphicsUnit.Pixel, bmpAttributes);
}
return bmp32BppDest;
}
}
希望这可以帮助。
局限性
- 请注意,如果使用太亮的颜色变换可能饱和。 为了保证没有饱和,TT是足够的R + G + B <= 1。
- 您可以通过将CR,CG,CB由CR + CG + CB标准化改造,但其中着色颜色为黑色处理的情况下,否则你会除以零。
Answer 5:
下面的代码构造一个ColorMatrix
用于施加色调偏移。
我有观点是在色调空间60°移:
实际上是在RGB空间中的45°相移:
这样你就可以把一个120°相移的一些部分成90°相移的一些部分。
该HueShift
参数必须是之间的值-1..1
。
例如,在为了施加60°移:
- 改变红色到黄色,
- 改变黄绿色
- 改变绿青色
- 改变青蓝色
- 将蓝光洋红色
- 改变品红红色
您致电:
var cm = GetHueShiftColorMatrix(60/360); //a value between 0..1
执行 :
function GetHueShiftColorMatrix(HueShift: Real): TColorMatrix;
var
theta: Real;
c, s: Real;
const
wedge = 120/360;
begin
if HueShift > 1 then
HueShift := 0
else if HueShift < -1 then
HueShift := 0
else if Hueshift < 0 then
HueShift := 1-HueShift;
if (HueShift >= 0) and (HueShift <= wedge) then
begin
//Red..Green
theta := HueShift / wedge*(pi/2);
c := cos(theta);
s := sin(theta);
cm[0, 0] := c; cm[0, 1] := 0; cm[0, 2] := s; cm[0, 3] := 0; cm[0, 4] := 0;
cm[1, 0] := s; cm[1, 1] := c; cm[1, 2] := 0; cm[1, 3] := 0; cm[1, 4] := 0;
cm[2, 0] := 0; cm[2, 1] := s; cm[2, 2] := c; cm[2, 3] := 0; cm[2, 4] := 0;
cm[3, 0] := 0; cm[3, 1] := 0; cm[3, 2] := 0; cm[3, 3] := 1; cm[3, 4] := 0;
cm[4, 0] := 0; cm[4, 1] := 0; cm[4, 2] := 0; cm[4, 3] := 0; cm[4, 4] := 1;
end
else if (HueShift >= wedge) and (HueShift <= (2*wedge)) then
begin
//Green..Blue
theta := (HueShift-wedge) / wedge*(pi/2);
c := cos(theta);
s := sin(theta);
cm[0, 0] := 0; cm[0, 1] := s; cm[0, 2] := c; cm[0, 3] := 0; cm[0, 4] := 0;
cm[1, 0] := c; cm[1, 1] := 0; cm[1, 2] := s; cm[1, 3] := 0; cm[1, 4] := 0;
cm[2, 0] := s; cm[2, 1] := c; cm[2, 2] := 0; cm[2, 3] := 0; cm[2, 4] := 0;
cm[3, 0] := 0; cm[3, 1] := 0; cm[3, 2] := 0; cm[3, 3] := 1; cm[3, 4] := 0;
cm[4, 0] := 0; cm[4, 1] := 0; cm[4, 2] := 0; cm[4, 3] := 0; cm[4, 4] := 1;
end
else
begin
//Blue..Red
theta := (HueShift-2*wedge) / wedge*(pi/2);
c := cos(theta);
s := sin(theta);
cm[0, 0] := s; cm[0, 1] := c; cm[0, 2] := 0; cm[0, 3] := 0; cm[0, 4] := 0;
cm[1, 0] := 0; cm[1, 1] := s; cm[1, 2] := c; cm[1, 3] := 0; cm[1, 4] := 0;
cm[2, 0] := c; cm[2, 1] := 0; cm[2, 2] := s; cm[2, 3] := 0; cm[2, 4] := 0;
cm[3, 0] := 0; cm[3, 1] := 0; cm[3, 2] := 0; cm[3, 3] := 1; cm[3, 4] := 0;
cm[4, 0] := 0; cm[4, 1] := 0; cm[4, 2] := 0; cm[4, 3] := 0; cm[4, 4] := 1;
end;
Result := cm;
end;
注意 :任何代码发布到公共领域。 无需归属。
Answer 6:
我想, www.aforgenet.com可以帮助
Answer 7:
我建立一个C#实现语言@IanBoid代码的方法。
public void setHueRotate(Bitmap bmpElement, float value) {
const float wedge = 120f / 360;
var hueDegree = -value % 1;
if (hueDegree < 0) hueDegree += 1;
var matrix = new float[5][];
if (hueDegree <= wedge)
{
//Red..Green
var theta = hueDegree / wedge * (Math.PI / 2);
var c = (float)Math.Cos(theta);
var s = (float)Math.Sin(theta);
matrix[0] = new float[] { c, 0, s, 0, 0 };
matrix[1] = new float[] { s, c, 0, 0, 0 };
matrix[2] = new float[] { 0, s, c, 0, 0 };
matrix[3] = new float[] { 0, 0, 0, 1, 0 };
matrix[4] = new float[] { 0, 0, 0, 0, 1 };
} else if (hueDegree <= wedge * 2)
{
//Green..Blue
var theta = (hueDegree - wedge) / wedge * (Math.PI / 2);
var c = (float) Math.Cos(theta);
var s = (float) Math.Sin(theta);
matrix[0] = new float[] {0, s, c, 0, 0};
matrix[1] = new float[] {c, 0, s, 0, 0};
matrix[2] = new float[] {s, c, 0, 0, 0};
matrix[3] = new float[] {0, 0, 0, 1, 0};
matrix[4] = new float[] {0, 0, 0, 0, 1};
}
else
{
//Blue..Red
var theta = (hueDegree - 2 * wedge) / wedge * (Math.PI / 2);
var c = (float)Math.Cos(theta);
var s = (float)Math.Sin(theta);
matrix[0] = new float[] {s, c, 0, 0, 0};
matrix[1] = new float[] {0, s, c, 0, 0};
matrix[2] = new float[] {c, 0, s, 0, 0};
matrix[3] = new float[] {0, 0, 0, 1, 0};
matrix[4] = new float[] {0, 0, 0, 0, 1};
}
Bitmap originalImage = bmpElement;
var imageAttributes = new ImageAttributes();
imageAttributes.ClearColorMatrix();
imageAttributes.SetColorMatrix(new ColorMatrix(matrix), ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
grpElement.DrawImage(
originalImage, elementArea,
0, 0, originalImage.Width, originalImage.Height,
GraphicsUnit.Pixel, imageAttributes
);
}
文章来源: Rotate Hue using ImageAttributes in C#