如何解决我需要对弯曲的矩形进行透视变换
有没有办法以某种方式旋转图像?我会向你解释:我不不想要PictureBox1.Image.RotateFlip(RotateFlipType.Rotate90FlipNone)
意义上的旋转,或者如图所示的here,而是将一个弯曲的矩形定向到相机(被与相机齐平)。
我做了一个 drawing for this。这是从上面的视图。想象一下,您是站在 (0,0) 点并正在拍摄身体照片的人 (“Rechteck”)。我想将该图像旋转某个角度,例如 35°,因为您与身体成 35°(透视)。
我已经准备了一些源代码并进行了计算。
代码的工作原理如下:用户必须输入他到矩形中心的距离以及角度。在附图中,这是红线。您还需要知道矩形的宽度。该程序计算 x 和 y 坐标(x_v
和 y_v
)。程序计算从矩形的左边缘到右边缘的所有距离和角度。
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace schiefes_Rechteck
{
public partial class Form_Main : Form
{
/// <summary>
/// entered angle in degrees
/// </summary>
private Int16 eingegebener_Winkel_in_Grad;
private UInt16 Radius_in_mm;
/// <summary>
/// Length of the rectangle in mm
/// </summary>
private UInt16 Laenge_des_Rechtecks_in_mm;
/// <summary>
/// all distances [mm]
/// </summary>
private List<double> alle_Entfernungen = new List<double>();
/// <summary>
/// all angles [°]
/// </summary>
private List<double> alle_Winkel = new List<double>();
public Form_Main()
{
InitializeComponent();
}
private void Form_Main_Load(object sender,EventArgs e)
{
this.BackColor = Color.FromArgb(148,148,109);
this.Location = new Point(0,0);
Button_Start.BackColor = Color.FromArgb(194,194,165);
TextBox_Entfernung.Text = "1300";
TextBox_Winkel.Text = "35";
TextBox_Rechtecklaenge.Text = "503";
if (System.IO.File.Exists(Application.StartupPath + "\\schiefes_Rechteck_Grafik.PNG"))
{
PictureBox1.Image = Image.FromFile(Application.StartupPath + "\\schiefes_Rechteck_Grafik.PNG");
}
}
private void Form_Main_FormClosing(object sender,FormClosingEventArgs e)
{
if (PictureBox1.Image != null)
{
PictureBox1.Image.dispose();
}
if (PictureBox2.Image != null)
{
PictureBox2.Image.dispose();
}
}
private void TextBox_Entfernung_TextChanged(object sender,EventArgs e)
{
if (!string.IsNullOrEmpty(TextBox_Entfernung.Text))
{
bool erfolgreich = UInt16.TryParse(TextBox_Entfernung.Text,out Radius_in_mm);
if (erfolgreich)
{
TextBox_Entfernung.ForeColor = Color.FromArgb(0,163,0);
}
else
{
TextBox_Entfernung.ForeColor = Color.FromArgb(163,0);
}
}
}
private void TextBox_Winkel_TextChanged(object sender,EventArgs e)
{
if (!string.IsNullOrEmpty(TextBox_Winkel.Text))
{
bool erfolgreich = Int16.TryParse(TextBox_Winkel.Text,out eingegebener_Winkel_in_Grad);
if (erfolgreich)
{
TextBox_Winkel.ForeColor = Color.FromArgb(0,0);
}
else
{
TextBox_Winkel.ForeColor = Color.FromArgb(163,0);
}
}
}
private void TextBox_Rechtecklaenge_TextChanged(object sender,EventArgs e)
{
if (!string.IsNullOrEmpty(TextBox_Rechtecklaenge.Text))
{
bool erfolgreich = UInt16.TryParse(TextBox_Rechtecklaenge.Text,out Laenge_des_Rechtecks_in_mm);
if (erfolgreich)
{
TextBox_Rechtecklaenge.ForeColor = Color.FromArgb(0,0);
}
else
{
TextBox_Rechtecklaenge.ForeColor = Color.FromArgb(163,0);
}
}
}
private async void Button_Start_Click(object sender,EventArgs e)
{
ListBox1.Items.Clear();
await Task.Run(() => Berechnung_aller_Werte());
}
private void Berechnung_aller_Werte()
{
alle_Entfernungen.Clear();
alle_Winkel.Clear();
double x_v,y_v; // Mitte des Rechtecks,davon die x-Koordinate und die y-Koordinate.
x_v = Radius_in_mm * Math.Cos((90.0 - (double)eingegebener_Winkel_in_Grad) * Math.PI / 180.0); //richtig
y_v = Radius_in_mm * Math.Sin((90.0 - (double)eingegebener_Winkel_in_Grad) * Math.PI / 180.0); //richtig
double alpha_in_Grad = 0.0;
double Entfernung = 0.0;
double halbe_Rechteckbreite = Laenge_des_Rechtecks_in_mm / 2.0;
double Position_linker_Rand = x_v - halbe_Rechteckbreite; //richtig
double Zaehler = 0.0;
while (Zaehler < Laenge_des_Rechtecks_in_mm)
{
alpha_in_Grad = Math.atan((Position_linker_Rand + Zaehler) / y_v) * 180.0 / Math.PI;
alle_Winkel.Add(alpha_in_Grad);
Entfernung = Math.Sqrt(Math.Pow(Position_linker_Rand + Zaehler,2) + Math.Pow(y_v,2));
alle_Entfernungen.Add(Entfernung);
Zaehler += 1.0;
}
this.BeginInvoke((Action)(() => { ListBox1.Items.Add(Math.Round(alle_Entfernungen.Last(),0).ToString() + " mm"); ListBox1.Items.Add(Math.Round(alle_Winkel.Last(),0).ToString() + " °"); }));
}
}//Form
}
解决方法
如果您想要一个不弯曲的图像,即所有线条保持垂直或水平,那么图像所发生的一切就是从侧面看它的宽度会显得更小,而其高度将保持不变。
通过将您看到图像的视在角度(即图像中黄绿色线和粉红色线之间的角度)除以您站立时的相应角度来获得 x 轴的缩放因子就在图像的前面。这个因素的一个非常好的近似值就是 cos(36° * PI / 180)
,其中角度是与图像中红线的角度。
xScale = Math.Cos(angleToMidLineInDegrees * Math.PI / 180);
yScale = 1;
或者干脆
xScale = Math.Cos(angleToMidLineInRadians);
yScale = 1;
哪里
angleToMidLineInRadians = Math.ATan(x_redLine / y_v);
或一步
xScale = y_v / Math.Sqrt(x_redLine * x_redLine + y_v * y_v);
参见:关于 WolframAlpha 的 cos(arctan(x/y))。
但是,在变换图像时,您必须进行逆变换(如 video 末尾所述),因为您要确定变换图像的像素。即,您将使用伪代码进行操作(其中 t
表示转换,没有 t
是原始坐标):
for (yt = 0 to height_t - 1; yt++) {
for (xt = 0 to width_t - 1; xt++) {
(x,y) = inverse_transformation(xt,yt);
color_t = get_color(picture,x,y);
draw(picture_t,xt,yt,color_t);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。