|
1
2
|
string
filename =
"source.jpg"
;
var
src = IplImage.FromFile(filename, LoadMode.GrayScale);
|
|
1
2
3
4
|
int
width = Cv.GetOptimalDFTSize(src.Width);
int
height = Cv.GetOptimalDFTSize(src.Height);
var
padded =
new
IplImage(width, height, BitDepth.U8, 1);
//擴展后的圖像,單通道
Cv.CopyMakeBorder(src, padded,
new
CvPoint(0, 0), BorderType.Constant, CvScalar.ScalarAll(0));
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//實部、虛部(單通道)
var
real =
new
IplImage(padded.Size, BitDepth.F32, 1);
var
imaginary =
new
IplImage(padded.Size, BitDepth.F32, 1);
//合成(雙通道)
var
fourier =
new
IplImage(padded.Size, BitDepth.F32, 2);
//圖像復制到實部,虛部清零
Cv.ConvertScale(padded, real);
Cv.Zero(imaginary);
//合並、變換、再分解
Cv.Merge(real, imaginary,
null
,
null
, fourier);
Cv.DFT(fourier, fourier, DFTFlag.Forward);
Cv.Split(fourier, real, imaginary,
null
,
null
);
|
|
1
2
3
4
5
6
7
8
9
10
11
12
|
//計算sqrt(re^2+im^2),再存回re
Cv.Pow(real, real, 2.0);
Cv.Pow(imaginary, imaginary, 2.0);
Cv.Add(real, imaginary, real);
Cv.Pow(real, real, 0.5);
//計算log(1+re),存回re
Cv.AddS(real, CvScalar.ScalarAll(1), real);
Cv.Log(real, real);
//歸一化
Cv.Normalize(real, real, 0, 1, NormType.MinMax);
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
/// <summary>
/// 將低頻部分移動到圖像中心
/// </summary>
/// <param name="image"></param>
/// <remarks>
/// 0 | 3 2 | 1
/// ------- ===> -------
/// 1 | 2 3 | 0
/// </remarks>
private
static
void
ShiftDFT(IplImage image)
{
int
row = image.Height;
int
col = image.Width;
int
cy = row / 2;
int
cx = col / 2;
var
q0 = image.Clone(
new
CvRect(0, 0, cx, cy));
//左上
var
q1 = image.Clone(
new
CvRect(0, cy, cx, cy));
//左下
var
q2 = image.Clone(
new
CvRect(cx, cy, cx, cy));
//右下
var
q3 = image.Clone(
new
CvRect(cx, 0, cx, cy));
//右上
Cv.SetImageROI(image,
new
CvRect(0, 0, cx, cy));
q2.Copy(image);
Cv.ResetImageROI(image);
Cv.SetImageROI(image,
new
CvRect(0, cy, cx, cy));
q3.Copy(image);
Cv.ResetImageROI(image);
Cv.SetImageROI(image,
new
CvRect(cx, cy, cx, cy));
q0.Copy(image);
Cv.ResetImageROI(image);
Cv.SetImageROI(image,
new
CvRect(cx, 0, cx, cy));
q1.Copy(image);
Cv.ResetImageROI(image);
}
|
|
1
2
|
Cv.Normalize(real, real, 0, 255, NormType.MinMax);
Cv.Threshold(real, real, 150, 255, ThresholdType.Binary);
|
|
1
2
3
4
5
6
7
|
//構造8UC1格式圖像
var
gray =
new
IplImage(real.Size, BitDepth.U8, 1);
Cv.ConvertScale(real, gray);
//找直線
var
storage = Cv.CreateMemStorage();
var
lines = Cv.HoughLines2(gray, storage, HoughLinesMethod.Standard, 1, Cv.PI / 180, 100);
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
float
angel = 0f;
float
piThresh = (
float
)Cv.PI / 90;
float
pi2 = (
float
)Cv.PI / 2;
for
(
int
i = 0; i < lines.Total; ++i)
{
//極坐標下的點,X是極徑,Y是夾角,我們只關心夾角
var
p = lines.GetSeqElem<CvPoint2D32f>(i);
float
theta = p.Value.Y;
if
(Math.Abs(theta) >= piThresh && Math.Abs(theta - pi2) >= piThresh)
{
angel = theta;
break
;
}
}
angel = angel < pi2 ? angel : (angel - (
float
)Cv.PI);
|
|
1
2
3
4
5
6
|
if
(angel != pi2)
{
float
angelT = (
float
)(src.Height * Math.Tan(angel) / src.Width);
angel = (
float
)Math.Atan(angelT);
}
float
angelD = angel * 180 / (
float
)Cv.PI;
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
var
center =
new
CvPoint2D32f(src.Width / 2.0, src.Height / 2.0);
//圖像中心
var
rotMat = Cv.GetRotationMatrix2D(center, angelD, 1.0);
//構造仿射變換矩陣
var
dst =
new
IplImage(src.Size, BitDepth.U8, 1);
//執行變換,產生的空白部分用255填充,即純白
Cv.WarpAffine(src, dst, rotMat, Interpolation.Cubic | Interpolation.FillOutliers, CvScalar.ScalarAll(255));
//展示
using
(
var
win =
new
CvWindow(
"Rotation"
))
{
win.Image = dst;
Cv.WaitKey();
}
|
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using OpenCvSharp.Utilities;
namespace OpenCvTest
{
class Program
{
static void Main(string[] args)
{
//以灰度方式讀入原文件
string filename = "source.jpg";
var src = IplImage.FromFile(filename, LoadMode.GrayScale);
//轉換到合適的大小,以適應快速變換
int width = Cv.GetOptimalDFTSize(src.Width);
int height = Cv.GetOptimalDFTSize(src.Height);
var padded = new IplImage(width, height, BitDepth.U8, 1);
Cv.CopyMakeBorder(src, padded, new CvPoint(0, 0), BorderType.Constant, CvScalar.ScalarAll(0));
//實部、虛部(單通道)
var real = new IplImage(padded.Size, BitDepth.F32, 1);
var imaginary = new IplImage(padded.Size, BitDepth.F32, 1);
//合並(雙通道)
var fourier = new IplImage(padded.Size, BitDepth.F32, 2);
//圖像復制到實部,虛部清零
Cv.ConvertScale(padded, real);
Cv.Zero(imaginary);
//合並、變換、再分解
Cv.Merge(real, imaginary, null, null, fourier);
Cv.DFT(fourier, fourier, DFTFlag.Forward);
Cv.Split(fourier, real, imaginary, null, null);
//計算sqrt(re^2+im^2),再存回re
Cv.Pow(real, real, 2.0);
Cv.Pow(imaginary, imaginary, 2.0);
Cv.Add(real, imaginary, real);
Cv.Pow(real, real, 0.5);
//計算log(1+re),存回re
Cv.AddS(real, CvScalar.ScalarAll(1), real);
Cv.Log(real, real);
//歸一化,落入0-255范圍
Cv.Normalize(real, real, 0, 255, NormType.MinMax);
//把低頻移動到中心
ShiftDFT(real);
//二值化,以150作為分界點,經驗值,需要根據實際情況調整
Cv.Threshold(real, real, 150, 255, ThresholdType.Binary);
//由於HoughLines2方法只接受8UC1格式的圖片,因此進行轉換
var gray = new IplImage(real.Size, BitDepth.U8, 1);
Cv.ConvertScale(real, gray);
//找直線,threshold參數取100,經驗值,需要根據實際情況調整
var storage = Cv.CreateMemStorage();
var lines = Cv.HoughLines2(gray, storage, HoughLinesMethod.Standard, 1, Cv.PI / 180, 100);
//找到符合條件的那條斜線
float angel = 0f;
float piThresh = (float)Cv.PI / 90;
float pi2 = (float)Cv.PI / 2;
for (int i = 0; i < lines.Total; ++i)
{
//極坐標下的點,X是極徑,Y是夾角,我們只關心夾角
var p = lines.GetSeqElem<CvPoint2D32f>(i);
float theta = p.Value.Y;
if (Math.Abs(theta) >= piThresh && Math.Abs(theta - pi2) >= piThresh)
{
angel = theta;
break;
}
}
angel = angel < pi2 ? angel : (angel - (float)Cv.PI);
Cv.ReleaseMemStorage(storage);
//轉換角度
if (angel != pi2)
{
float angelT = (float)(src.Height * Math.Tan(angel) / src.Width);
angel = (float)Math.Atan(angelT);
}
float angelD = angel * 180 / (float)Cv.PI;
Console.WriteLine("angtlD = {0}", angelD);
//旋轉
var center = new CvPoint2D32f(src.Width / 2.0, src.Height / 2.0);
var rotMat = Cv.GetRotationMatrix2D(center, angelD, 1.0);
var dst = new IplImage(src.Size, BitDepth.U8, 1);
Cv.WarpAffine(src, dst, rotMat, Interpolation.Cubic | Interpolation.FillOutliers, CvScalar.ScalarAll(255));
//顯示
using (var window = new CvWindow("Image"))
{
window.Image = src;
using (var win2 = new CvWindow("Dest"))
{
win2.Image = dst;
Cv.WaitKey();
}
}
}
/// <summary>
/// 將低頻部分移動到圖像中心
/// </summary>
/// <param name="image"></param>
/// <remarks>
/// 0 | 3 2 | 1
/// ------- ===> -------
/// 1 | 2 3 | 0
/// </remarks>
private static void ShiftDFT(IplImage image)
{
int row = image.Height;
int col = image.Width;
int cy = row / 2;
int cx = col / 2;
var q0 = image.Clone(new CvRect(0, 0, cx, cy));//左上
var q1 = image.Clone(new CvRect(0, cy, cx, cy));//左下
var q2 = image.Clone(new CvRect(cx, cy, cx, cy));//右下
var q3 = image.Clone(new CvRect(cx, 0, cx, cy));//右上
Cv.SetImageROI(image, new CvRect(0, 0, cx, cy));
q2.Copy(image);
Cv.ResetImageROI(image);
Cv.SetImageROI(image, new CvRect(0, cy, cx, cy));
q3.Copy(image);
Cv.ResetImageROI(image);
Cv.SetImageROI(image, new CvRect(cx, cy, cx, cy));
q0.Copy(image);
Cv.ResetImageROI(image);
Cv.SetImageROI(image, new CvRect(cx, 0, cx, cy));
q1.Copy(image);
Cv.ResetImageROI(image);
}
}
}
附件列表





