Files
cameramanager/CameraMng/clsImageMng/clsImageMng.vb
T
2025-07-21 11:41:13 +02:00

1171 lines
40 KiB
VB.net

Imports System.Runtime
Imports Emgu.CV.CvEnum
Imports Emgu.CV.Structure
Imports System.Math
Imports System.IO
Imports System.Globalization
Imports Emgu.CV
Imports System.Threading
Imports Emgu.CV.Util
Imports System.Drawing.Imaging
Public Class clsImageMng
#Region "membri privati"
Private m_dimx As Short = 1 '3888
Private m_dimy As Short = 1 ' 2592
Private m_Pos_x_mm, m_Pos_y_mm As Double
' Posizione in mm del punto_3 (ibl=3) rispetto all'origine (punto_0)
Private m_Pos_x_z0_mm, m_Pos_y_z0_mm As Double
Private m_bCorrected As Boolean = False
Private m_pmm_bs As New clPuntomm
Private m_pmm_bs_lev0 As New clPuntomm
Private m_scale_center As New clPuntomm
Private m_fscalaxmm As Double
Private m_scale_centerZ As Double
Private m_punto0 As New clCoppiaPunto
Private m_puntoH(4) As clCoppiaPunto
Private m_bCorrAltezzaEnabled As Boolean
' posizione in px dei punti dell'immagine originale rispetto al punto punto_0 (itl=0)
Private m_pdst(3) As System.Drawing.PointF ' punti nuova foto
' indice per distinguere i punti salvati nei vettori 'm_pworld', 'm_psrc', 'm_pdst'
Const itl As Integer = 0 ' top left
Const itr As Integer = 1 ' top right
Const ibl As Integer = 3 ' Bottom right
Const ibr As Integer = 2 ' Bottom left
' Dimensione immagine dopo aver calcolato le estensioni oltre al riquadro
Private m_dim_XProsp As Short = 1 ' dimens. img con prospettiva corretta
Private m_dim_YProsp As Short = 1
' mm to px all'altezza zero del tavolo
Private m_mm2PixelProspZ0 As Double
Private m_mm2PixelProspFinal As Double
' Estension in Pixel dell'immagine
Private m_ExtXL_pix As Integer, m_ExtXR_pix As Integer ' sinistra e destra
Private m_ExtYT_pix As Integer, m_ExtYB_pix As Integer ' sopra e sotto
' Estension in mm dell'immagine
Private m_ExtXL_mm As Single, m_ExtXR_mm As Single ' sinistra e destra
Private m_ExtYT_mm As Single, m_ExtYB_mm As Single ' sopra e sotto
#If WinXP Then
Private m_MatDir As Matrix(Of Double) 'HomographyMatrix ' Per creare l'immagine correttta, data la coord. XY, mi dà il pixel da prendere
Private m_MatInv As Matrix(Of Double) 'HomographyMatrix ' Per ottenere la coord. in mm da un valore in pixel dell'imm. originale
#Else
' 'HomographyMatrix' matrice di correzione prospettica (dalle in pixel a quelle world) 'HomographyMatrix '
Private m_MatInv(2, 2) As Double
' 'HomographyMatrix' matrice di correzione prospettica (dalle coordinate world a quelle locali in px)
Private m_MatDir(2, 2) As Double
#End If
Private m_NomeFileCorrezProsp As String
Private m_ProspCalibrated As Boolean = False
Private m_SpessLastra As Double = 0
Private m_SpessCorr As Double = 0
Private _thprocess As Thread = Nothing
Private m_UndistImage As Drawing.Bitmap = Nothing
Private m_FinalImage As Drawing.Bitmap = Nothing
Private m_InputImage As Drawing.Bitmap = Nothing
Private m_dim_XProspExt As Integer
Private m_dim_YProspExt As Integer
Private m_FileCalibLens As String = Nothing
Private m_FileCalibProsp As String = Nothing
Private m_widthImagePixMax As Integer = 6000
Private MatConvP(m_dimx, m_dimy) As clPuntoPix
Private m_CalimageWidth As Integer = 0
' [ fx 0.0 cx
' 0.0 fy cy
' 0.0 0.0 1.0 ]
Private _cameraMatrix As Matrix(Of Double) = Nothing
' [ k1, k2, p1, p2, p3 ]
Private _distCoeffs As Matrix(Of Double) = Nothing
Private Shared ReadOnly m_sync As New Object
' vettore di correzione prospettica: convertita in matrice (m_MatDir)
Private _perspMatDir As Emgu.CV.Mat
Private _ocvMapx As Emgu.CV.Matrix(Of Single)
Private _ocvMapy As Emgu.CV.Matrix(Of Single)
Private m_jpgQuality As Long = 80
#End Region
#Region "membri pubblici"
Public m_fileCaliLensRead As Boolean = False
Public m_fileCaliProspRead As Boolean = False
Public m_bMatProspOk As Boolean = False
' --- variabili per la correzione prospettica
Public m_AltRif As Double
Public m_ZCali As Double
' punti world in mm riferiti rispetto all'origine punto_0 (itl=0)
Public m_pworld(3) As System.Drawing.PointF
' punti foto riferiti rispetto all'origine immagine
Public m_psrc(3) As System.Drawing.PointF
#End Region
#Region "eventi"
Public Event FineCorrezioneLente()
Public Event FineCorrezioneProspettiva()
Public Event AvanzamentoCorrezioneLente(value As Double)
Public Event AvanzamentoCorrezioneProspettiva(value As Double)
Public Event ProcessAborted(err As Integer)
#End Region
#Region "Classi Private"
Private Class clPuntoPix
Public X As Single
Public Y As Single
End Class
Private Class clPuntomm
Public x As Double
Public y As Double
End Class
Private Class clCoppiaPunto
Public XTrg As Double
Public YTrg As Double
Public XSrc As Double
Public YSrc As Double
End Class
#End Region
#Region "Costruttori"
Public Sub New()
Dim i As Integer
For i = 0 To 3
If IsNothing(m_puntoH(i)) Then m_puntoH(i) = New clCoppiaPunto
Next
m_ProspCalibrated = False
End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
End Sub
#End Region
#Region "Proprietà"
Public ReadOnly Property UndistorcedImage As Bitmap
Get
SyncLock m_sync
Return m_UndistImage
End SyncLock
End Get
End Property
Public ReadOnly Property FinalImage As Bitmap
Get
SyncLock m_sync
Return m_FinalImage
End SyncLock
End Get
End Property
Public Property InputImage As Bitmap
Get
Return m_InputImage
End Get
Set(value As Bitmap)
m_InputImage = value
End Set
End Property
Public Property MaxPxWidthOutImage As Integer
Set(value As Integer)
m_widthImagePixMax = value
End Set
Get
Return m_widthImagePixMax
End Get
End Property
Public ReadOnly Property mm2pixelAtZ As Double
Get
Return m_mm2PixelProspFinal
End Get
End Property
#End Region
#Region "Metodi Pubblici"
Public Function SetFileCalibrazione(NomeFileCaliLens As String, NomeFileCaliProsp As String) As Boolean
m_FileCalibLens = NomeFileCaliLens
m_FileCalibProsp = NomeFileCaliProsp
Return True
End Function
Public Sub Correggi()
' corregge solo la lente e carica il file di calibrazione prospettiva per dare la possibilità di calibrare dall'interfaccia
Try
If Not m_fileCaliLensRead Then
m_fileCaliLensRead = LeggiFileCalibrazioneLenteOCV(m_FileCalibLens)
End If
If Not m_fileCaliProspRead Then
m_fileCaliProspRead = LeggiFileCorrezProsp(m_FileCalibProsp)
End If
If Not m_UndistImage Is Nothing Then
'm_UndistImage.Dispose()
m_UndistImage = Nothing
End If
Dim outFrame As New Image(Of Emgu.CV.Structure.Rgb, Byte)(m_InputImage.Width, m_InputImage.Height)
Dim newIntrinsecMatrix As IInputArray
CvInvoke.Undistort(New Image(Of Emgu.CV.Structure.Rgb, Byte)(m_InputImage), outFrame, _cameraMatrix, _distCoeffs, newIntrinsecMatrix)
m_UndistImage = outFrame.Bitmap
GC.Collect()
m_UndistImage.Save(DirTmp & "corrected.bmp", System.Drawing.Imaging.ImageFormat.Bmp)
m_bCorrected = True
RaiseEvent AvanzamentoCorrezioneProspettiva(100)
Catch ex As Exception
If Not m_UndistImage Is Nothing Then
'm_UndistImage.Dispose()
m_UndistImage = Nothing
End If
Throw New Exception(ex.Message)
End Try
End Sub
Public Sub DownloadCompletato()
m_bCorrected = False
End Sub
'* c00*xi + c01*yi + c02
'* ui = ---------------------
'* c20*xi + c21*yi + c22
'*
'* c10*xi + c11*yi + c12
'* vi = ---------------------
'* c20*xi + c21*yi + c22
Public Sub CorreggiProspettiva(ByVal SpessLastra As Double)
If Not m_bMatProspOk Then
CalcolaMatriceCorrezioneProspettiva()
CalcolaMatriceOCV()
End If
If m_bMatProspOk Then
CorreggiProspettivaDaMatriceOCV(SpessLastra)
End If
End Sub
Public Sub CalcolaDatiCorrezione()
' forzo il ricalcolo
m_ProspCalibrated = False
CalcolaDatiCorrezioneDiretta()
CalcolaDatiCorrezioneInversa()
m_bCorrAltezzaEnabled = True
If Not TrovaDatiScalatura() Then m_bCorrAltezzaEnabled = False
If Not TrovaOffsetPosizione() Then m_bCorrAltezzaEnabled = False
End Sub
' Salvo file di calibrazione
Public Sub SalvaFileCorrezioneProsp()
Dim writer As StreamWriter
Dim i As Integer
Dim nfi As New CultureInfo("en-US", False)
writer = New StreamWriter(m_NomeFileCorrezProsp)
writer.WriteLine("ProspPnt")
For i = 0 To 3
writer.WriteLine("{0} {1} {2} {3}", m_pworld(i).X.ToString("0.00", nfi.NumberFormat), m_pworld(i).Y.ToString("0.00", nfi.NumberFormat),
m_psrc(i).X.ToString("0", nfi.NumberFormat), m_psrc(i).Y.ToString("0", nfi.NumberFormat))
Next
writer.WriteLine("Extend={0} {1} {2} {3}", m_ExtXL_mm.ToString("0", nfi.NumberFormat), m_ExtXR_mm.ToString("0", nfi.NumberFormat), m_ExtYT_mm.ToString("0", nfi.NumberFormat), m_ExtYB_mm.ToString("0", nfi.NumberFormat))
writer.WriteLine("AltRif= {0}", m_AltRif.ToString("0.00", nfi.NumberFormat))
writer.WriteLine("p1Rif= {0} {1} {2} {3}", m_puntoH(0).XSrc, m_puntoH(0).YSrc, m_puntoH(1).XSrc, m_puntoH(1).YSrc)
writer.WriteLine("p2Rif= {0} {1} {2} {3}", m_puntoH(2).XSrc, m_puntoH(2).YSrc, m_puntoH(3).XSrc, m_puntoH(3).YSrc)
writer.WriteLine("ZCali= {0}", m_ZCali.ToString("0.00", nfi.NumberFormat))
m_CalimageWidth = 0
If m_InputImage IsNot Nothing Then
m_CalimageWidth = m_InputImage.Width
End If
writer.WriteLine("ImageWidth= {0}", m_CalimageWidth.ToString("0"))
writer.Close()
CalcolaMatriceCorrezioneProspettiva()
' Avviso che la configurazione è stata salvata correttamente
Dim sMsg = String.Format("Salvataggio file di calbrazione '{0}' " & vbCrLf & "avvenuto con succeso!", m_NomeFileCorrezProsp)
MessageBox.Show(sMsg, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
Public Sub ProcessStop()
If _thprocess Is Nothing Then Exit Sub
If _thprocess.IsAlive Then
_thprocess.Abort()
_thprocess = Nothing
End If
End Sub
Public Sub CorrezioneCompletaAsync()
ProcessStop()
_thprocess = New Thread(Sub()
CorrezioneCompleta()
End Sub)
_thprocess.Start()
End Sub
Public Sub SaveBitmap(bitm As Bitmap, fileName As String)
' Encoder parameter for image quality
Dim qualityParam As New EncoderParameter(Encoder.Quality, m_jpgQuality)
' Jpeg image codec
Dim jpegCodec As ImageCodecInfo = GetEncoderInfo("image/jpeg")
Dim encoderParams As New EncoderParameters(1)
encoderParams.Param(0) = qualityParam
bitm.Save(fileName, jpegCodec, encoderParams)
End Sub
#End Region
#Region "Metodi Privati"
Private Function TrovaPuntoInmm4p(ByVal p As clCoppiaPunto) As Boolean
p.XTrg = (m_MatInv(0, 0) * p.XSrc + m_MatInv(0, 1) * p.YSrc + m_MatInv(0, 2)) / (m_MatInv(2, 0) * p.XSrc + m_MatInv(2, 1) * p.YSrc + m_MatInv(2, 2))
p.YTrg = (m_MatInv(1, 0) * p.XSrc + m_MatInv(1, 1) * p.YSrc + m_MatInv(1, 2)) / (m_MatInv(2, 0) * p.XSrc + m_MatInv(2, 1) * p.YSrc + m_MatInv(2, 2))
TrovaPuntoInmm4p = True
End Function
Private Function TrovaDatiScalatura() As Boolean
' trova il centro di scala e il fattore di scala in altezza, per mm
Dim a1, b1, c1, a2, b2, c2 As Double
Dim denominatore As Double
TrovaDatiScalatura = False
' posizione in mm
m_fscalaxmm = 1
If (m_AltRif <= 0.1) Then Exit Function
If Not TrovaPuntoInmm4p(m_puntoH(0)) Then Exit Function
If Not TrovaPuntoInmm4p(m_puntoH(1)) Then Exit Function
If Not TrovaPuntoInmm4p(m_puntoH(2)) Then Exit Function
If Not TrovaPuntoInmm4p(m_puntoH(3)) Then Exit Function
a1 = m_puntoH(0).YTrg - m_puntoH(1).YTrg
b1 = -(m_puntoH(0).XTrg - m_puntoH(1).XTrg)
c1 = -m_puntoH(1).XTrg * a1 - m_puntoH(1).YTrg * b1
a2 = m_puntoH(2).YTrg - m_puntoH(3).YTrg
b2 = -(m_puntoH(2).XTrg - m_puntoH(3).XTrg)
c2 = -m_puntoH(3).XTrg * a2 - m_puntoH(3).YTrg * b2
denominatore = a1 * b2 - a2 * b1
' centro di scala
If Abs(denominatore) > 0.0001 Then
m_scale_center.y = (a2 * c1 - a1 * c2) / denominatore
m_scale_center.x = (b1 * c2 - b2 * c1) / denominatore
Else
Exit Function
End If
Dim distl, disth As Double
distl = (m_scale_center.x - m_puntoH(0).XTrg) * (m_scale_center.x - m_puntoH(0).XTrg) + (m_scale_center.y - m_puntoH(0).YTrg) * (m_scale_center.y - m_puntoH(0).YTrg)
distl = Math.Sqrt(distl)
disth = (m_scale_center.x - m_puntoH(1).XTrg) * (m_scale_center.x - m_puntoH(1).XTrg) + (m_scale_center.y - m_puntoH(1).YTrg) * (m_scale_center.y - m_puntoH(1).YTrg)
disth = Math.Sqrt(disth)
m_fscalaxmm = distl / disth
m_fscalaxmm = Pow(m_fscalaxmm, 1 / m_AltRif)
m_scale_centerZ = m_ZCali + m_AltRif / (1 - distl / disth)
TrovaDatiScalatura = True
End Function
Private Function TrovaOffsetPosizione() As Boolean
Dim pt As New clPuntomm
Dim pTmp As New clCoppiaPunto
Dim offset As New clPuntomm ' calcolato
Try
' trovo come si trasforma in mm (senza offset) il punto di origine in pixel
pTmp.XSrc = m_punto0.XSrc
pTmp.YSrc = m_punto0.YSrc
If Not TrovaPuntoInmm4p(pTmp) Then Return False
' Trovo quindi l'offset dato dal punto di riferimento
offset.x = m_punto0.XTrg - pTmp.XTrg
offset.y = m_punto0.YTrg - pTmp.YTrg
' Trovo dove si trova il punto in pixel in basso a sin
m_pmm_bs_lev0.x = m_pmm_bs.x + offset.x
m_pmm_bs_lev0.y = m_pmm_bs.y + offset.y
Catch ex As Exception
Return False
End Try
Return True
End Function
#Region "Lettura configurazioni"
''' <summary>
''' Legge il file che contiene i parametri di correzione della lente
''' </summary>
''' <param name="NomeFile">Percorso file da leggere</param>
''' <returns>Ritorna True se la lettura è andata a buon fine</returns>
Private Function LeggiFileCalibrazioneLenteOCV(NomeFile As String) As Boolean
Console.WriteLine("LETTURA OCV: " & MainModule.IndexProc)
Dim Linea As String
Dim split() As String
Dim reader As StreamReader
Dim i, j As Integer
Dim nfi As NumberFormatInfo = New CultureInfo("en-US", False).NumberFormat
Dim CalibType As Integer = 0
Dim FileVersion As Integer = 0
If _cameraMatrix Is Nothing Then
_cameraMatrix = New Matrix(Of Double)(3, 3)
End If
If _distCoeffs Is Nothing Then
_distCoeffs = New Matrix(Of Double)(1, 4)
End If
'CalibType = 1
'FileVersion = 1
'rms = 2.912043
'fx = 4775.944905
'fy = 4775.944905
'cx = 3103.561924
'cy = 2033.648165
'k1 = -0.153547
'k2 = 0.127935
'p1 = -0.00626
'p2 = -0.000005
'hfov = 66Deg
'vfov = 46.1Deg
'[fx 0 cx; 0 fy cy; 0 0 1]
' setto i coefficenti fissi:
_cameraMatrix.Data(0, 1) = 0
_cameraMatrix.Data(1, 0) = 0
_cameraMatrix.Data(2, 0) = 0
_cameraMatrix.Data(2, 1) = 0
_cameraMatrix.Data(2, 2) = 1
Try
nfi.NumberDecimalSeparator = "."
reader = New StreamReader(NomeFile)
While (Not reader.EndOfStream)
Linea = reader.ReadLine()
split = Linea.Split(" =", 5, StringSplitOptions.RemoveEmptyEntries)
If split.Length > 0 Then
If split(0).Equals("CalibType", StringComparison.InvariantCultureIgnoreCase) Then
CalibType = CInt(split(1))
ElseIf split(0).Equals("FileVersion", StringComparison.InvariantCultureIgnoreCase) Then
FileVersion = CInt(split(1))
ElseIf (Linea.StartsWith("rms")) Then
' non carico dato
' CAMERA MATRIX
ElseIf (Linea.StartsWith("fx")) Then
_cameraMatrix.Data(0, 0) = Convert.ToDouble(split(1), nfi)
ElseIf (Linea.StartsWith("cx")) Then
_cameraMatrix.Data(0, 2) = Convert.ToDouble(split(1), nfi)
ElseIf (Linea.StartsWith("fy")) Then
_cameraMatrix.Data(1, 1) = Convert.ToDouble(split(1), nfi)
ElseIf (Linea.StartsWith("cy")) Then
_cameraMatrix.Data(1, 2) = Convert.ToDouble(split(1), nfi)
' DISTORSION COEFFICIENT
ElseIf (Linea.StartsWith("k1")) Then
_distCoeffs.Data(0, 0) = Convert.ToDouble(split(1), nfi)
ElseIf (Linea.StartsWith("k2")) Then
_distCoeffs.Data(0, 1) = Convert.ToDouble(split(1), nfi)
ElseIf (Linea.StartsWith("p1")) Then
_distCoeffs.Data(0, 2) = Convert.ToDouble(split(1), nfi)
ElseIf (Linea.StartsWith("p2")) Then
_distCoeffs.Data(0, 3) = Convert.ToDouble(split(1), nfi)
ElseIf (Linea.StartsWith("hfov")) Then
' non carico dato
ElseIf (Linea.StartsWith("vfov")) Then
' non carico dato
ElseIf (Linea.StartsWith("ImageWidth")) Then
' non carico dato
ElseIf (Linea.StartsWith("ImageHeight")) Then
' non carico dato
End If
End If
End While
reader.Close()
reader.Dispose()
Console.WriteLine("LETTURA OCV TERMINATA: " & MainModule.IndexProc)
If CalibType <> 1 Then
MsgBox("Calibration Type error in file: " & NomeFile)
End If
If FileVersion <> 1 Then
MsgBox("FileVersion error in file: " & NomeFile)
End If
' alla prima acquisizione immagine si controllerà
' controllare se le dimensioni dell'immagine usata per la calibrazione coincidono con quelle attuali
' ScalaCalibrazione()
' If creaMatrice Then
' CreaMatriceCalibrazione()
' End If
Catch ex As Exception
MsgBox("Calibration error : " & NomeFile)
Return False
End Try
Return True
End Function
''' <summary>
''' Lettura del file per la risoluzione della distorsione prospettica
''' </summary>
''' <param name="NomeFile">Percorso del file da leggere</param>
''' <returns>Ritorna True se la lettura è andata a buon fine</returns>
Private Function LeggiFileCorrezProsp(ByVal NomeFile As String) As Boolean
' nome file: Calib.txt
Dim Linea As String
Dim delimStr As String
Dim delimiter(5) As Char
Dim split() As String
Dim reader As StreamReader
Dim i As Integer
Dim nfi As NumberFormatInfo = New CultureInfo("en-US", False).NumberFormat
Try
m_NomeFileCorrezProsp = NomeFile
delimStr = " ="
delimiter = delimStr.ToCharArray()
nfi.NumberDecimalSeparator = "."
reader = New StreamReader(NomeFile)
' m_nPixOut = 0
While (Not reader.EndOfStream)
Linea = reader.ReadLine()
If (Linea.StartsWith("ProspPnt")) Then
For i = 0 To 3
Linea = reader.ReadLine()
split = Linea.Split(delimiter, 8, StringSplitOptions.RemoveEmptyEntries)
m_pworld(i).X = Convert.ToSingle(split(0), nfi)
m_pworld(i).Y = Convert.ToSingle(split(1), nfi)
m_psrc(i).X = Convert.ToSingle(split(2), nfi)
m_psrc(i).Y = Convert.ToSingle(split(3), nfi)
Next
ElseIf (Linea.StartsWith("Extend=")) Then
split = Linea.Split(delimiter, 8, StringSplitOptions.RemoveEmptyEntries)
m_ExtXL_mm = Convert.ToSingle(split(1), nfi)
m_ExtXR_mm = Convert.ToSingle(split(2), nfi)
m_ExtYT_mm = Convert.ToSingle(split(3), nfi)
m_ExtYB_mm = Convert.ToSingle(split(4), nfi)
ElseIf (Linea.StartsWith("AltRif=")) Then
split = Linea.Split(delimiter, 5, StringSplitOptions.RemoveEmptyEntries)
m_AltRif = Convert.ToDouble(split(1), nfi)
ElseIf (Linea.StartsWith("p1Rif=")) Then
split = Linea.Split(delimiter, 8, StringSplitOptions.RemoveEmptyEntries)
m_puntoH(0).XSrc = Convert.ToDouble(split(1))
m_puntoH(0).YSrc = Convert.ToDouble(split(2))
m_puntoH(1).XSrc = Convert.ToDouble(split(3))
m_puntoH(1).YSrc = Convert.ToDouble(split(4))
ElseIf (Linea.StartsWith("p2Rif=")) Then
split = Linea.Split(delimiter, 8, StringSplitOptions.RemoveEmptyEntries)
m_puntoH(2).XSrc = Convert.ToDouble(split(1))
m_puntoH(2).YSrc = Convert.ToDouble(split(2))
m_puntoH(3).XSrc = Convert.ToDouble(split(3))
m_puntoH(3).YSrc = Convert.ToDouble(split(4))
ElseIf (Linea.StartsWith("ZCali=")) Then
split = Linea.Split(delimiter, 8, StringSplitOptions.RemoveEmptyEntries)
m_ZCali = Convert.ToDouble(split(1), nfi)
ElseIf (Linea.StartsWith("ImageWidth=")) Then
split = Linea.Split(delimiter, 8, StringSplitOptions.RemoveEmptyEntries)
m_CalimageWidth = Convert.ToDouble(split(1), nfi)
End If
End While
reader.Close()
reader.Dispose()
Catch ex As Exception
MsgBox("Missing file : " & NomeFile)
Return False
End Try
CalcolaDatiCorrezione()
Return True
End Function
#End Region ' Lettura configurazioni
Property Corrected() As Boolean
Get
Return m_bCorrected
End Get
Set(ByVal value As Boolean)
m_bCorrected = value
End Set
End Property
ReadOnly Property CorrAltEnabled() As Boolean
Get
Return m_bCorrAltezzaEnabled
End Get
End Property
ReadOnly Property ZCali() As Double
Get
Return m_ZCali
End Get
End Property
Property XHpix(ByVal i As Integer) As Short
Get
Return (m_puntoH(i).XSrc)
End Get
Set(ByVal value As Short)
m_puntoH(i).XSrc = value
End Set
End Property
Property YHpix(ByVal i As Integer) As Short
Get
Return (m_puntoH(i).YSrc)
End Get
Set(ByVal value As Short)
m_puntoH(i).YSrc = value
End Set
End Property
#Region "Caolcolo matrici di correzione prospettica"
''' <summary>
''' Ottine la matrice 'm_MatDir' di correzione prospettica
''' Viene richiamato il metodo 'CalcolaDatiCorrezioneDiretta'
''' </summary>
Private Sub CalcolaDatiCorrezioneDiretta()
' L'immagine da rettificare non è un rettangolo
CalcolaDatiCorrezioneDirettaNoRett()
' Se ' CalcolaDatiCorrezioneDirettaNoRett' andata a buon fine 'm_ProspCalibrated=true'
If m_ProspCalibrated Then Exit Sub
' -- ALGORITMO ABBANDONATO --
Dim distmm As Double, distpix As Double, mm2pix As Double
Dim distXMax As Double, distYMax As Double
' prendo i pixel per mm più adeguati per non perdere informazioni
'lato sopra tl-tr (itl=0, itr=1)
distmm = Math.Sqrt(Math.Pow(m_pworld(itl).X - m_pworld(itr).X, 2) + Math.Pow(m_pworld(itl).Y - m_pworld(itr).Y, 2))
distpix = Math.Sqrt(Math.Pow(m_psrc(itl).X - m_psrc(itr).X, 2) + Math.Pow(m_psrc(itl).Y - m_psrc(itr).Y, 2))
mm2pix = distpix / distmm ' pixel per mm
distXMax = distmm
'lato sotto bl-br (ibl=3, ibr=2)
distmm = Math.Sqrt(Math.Pow(m_pworld(ibl).X - m_pworld(ibr).X, 2) + Math.Pow(m_pworld(ibl).Y - m_pworld(ibr).Y, 2))
distpix = Math.Sqrt(Math.Pow(m_psrc(ibl).X - m_psrc(ibr).X, 2) + Math.Pow(m_psrc(ibl).Y - m_psrc(ibr).Y, 2))
If (distpix / distmm > mm2pix) Then mm2pix = distpix / distmm
If (distmm > distXMax) Then distXMax = distmm
'lato sinistro tl-bl (itl=0, ibl=3)
distmm = Math.Sqrt(Math.Pow(m_pworld(itl).X - m_pworld(ibl).X, 2) + Math.Pow(m_pworld(itl).Y - m_pworld(ibl).Y, 2))
distpix = Math.Sqrt(Math.Pow(m_psrc(itl).X - m_psrc(ibl).X, 2) + Math.Pow(m_psrc(itl).Y - m_psrc(ibl).Y, 2))
If (distpix / distmm > mm2pix) Then mm2pix = distpix / distmm
distYMax = distmm
'lato destro tr-br (itr=1, ibr=2)
distmm = Math.Sqrt(Math.Pow(m_pworld(itr).X - m_pworld(ibr).X, 2) + Math.Pow(m_pworld(itr).Y - m_pworld(ibr).Y, 2))
distpix = Math.Sqrt(Math.Pow(m_psrc(itr).X - m_psrc(ibr).X, 2) + Math.Pow(m_psrc(itr).Y - m_psrc(ibr).Y, 2))
If (distpix / distmm > mm2pix) Then mm2pix = distpix / distmm
If (distmm > distYMax) Then distYMax = distmm
' -- verifico che l'immagine non sia troppo grande
Dim widthImagePix As Double = (distXMax + m_ExtXL_mm + m_ExtXR_mm) * mm2pix
If widthImagePix > m_widthImagePixMax Then
mm2pix = mm2pix * CDbl(m_widthImagePixMax) / widthImagePix
End If
' allora la nostra nuova bitmap sarà:
m_dim_XProsp = Convert.ToInt16(distXMax * mm2pix)
m_dim_YProsp = Convert.ToInt16(distYMax * mm2pix)
m_mm2PixelProspZ0 = mm2pix
m_ExtXL_pix = Convert.ToInt16(m_ExtXL_mm * m_mm2PixelProspZ0)
m_ExtXR_pix = Convert.ToInt16(m_ExtXR_mm * m_mm2PixelProspZ0)
m_ExtYT_pix = Convert.ToInt16(m_ExtYT_mm * m_mm2PixelProspZ0)
m_ExtYB_pix = Convert.ToInt16(m_ExtYB_mm * m_mm2PixelProspZ0)
' -- ALGORITMO DEPRECATO --
' perchè considera la figura perfettamente rettangolo con i lati paralleli all'immagine
m_pdst(itl).X = 0 : m_pdst(itl).Y = 0
m_pdst(itr).X = m_dim_XProsp : m_pdst(itr).Y = 0
m_pdst(ibl).X = 0 : m_pdst(ibl).Y = m_dim_YProsp
m_pdst(ibr).X = m_dim_XProsp : m_pdst(ibr).Y = m_dim_YProsp
#If WinXP Then
m_MatDir = Emgu.CV.CameraCalibration.GetPerspectiveTransform(m_pdst, m_psrc) 'scambio dest e source!
#Else
_perspMatDir = CvInvoke.GetPerspectiveTransform(m_pdst, m_psrc)
' unico modo che ho trovato per passare a mia matrice
Dim hh(8) As Double
_perspMatDir.CopyTo(Of Double)(hh)
For i = 0 To 2
For j = 0 To 2
m_MatDir(i, j) = hh(i * 3 + j)
Next
Next
#End If
m_Pos_x_z0_mm = m_pworld(ibl).X - m_ExtXL_mm
m_Pos_y_z0_mm = m_pworld(ibl).Y - m_ExtYB_mm
m_ProspCalibrated = True
End Sub
''' <summary>
''' Ottiene la matrice 'm_MatDir' per la correzione prospettica nel piano Z=0
''' </summary>
Private Sub CalcolaDatiCorrezioneDirettaNoRett()
Dim distmm As Double, distpix As Double, mm2pix As Double
Dim distXMax As Double, distYMax As Double
If m_ProspCalibrated Then Exit Sub
' prendo i pixel per mm più adeguati per non perdere informazioni
'lato sopra tl-tr
distmm = Math.Sqrt(Math.Pow(m_pworld(itl).X - m_pworld(itr).X, 2) + Math.Pow(m_pworld(itl).Y - m_pworld(itr).Y, 2))
distXMax = distmm
distpix = Math.Sqrt(Math.Pow(m_psrc(itl).X - m_psrc(itr).X, 2) + Math.Pow(m_psrc(itl).Y - m_psrc(itr).Y, 2))
mm2pix = distpix / distmm ' pixel per mm
'lato sotto bl-br
distmm = Math.Sqrt(Math.Pow(m_pworld(ibl).X - m_pworld(ibr).X, 2) + Math.Pow(m_pworld(ibl).Y - m_pworld(ibr).Y, 2))
distpix = Math.Sqrt(Math.Pow(m_psrc(ibl).X - m_psrc(ibr).X, 2) + Math.Pow(m_psrc(ibl).Y - m_psrc(ibr).Y, 2))
If (distpix / distmm > mm2pix) Then mm2pix = distpix / distmm
If (distmm > distXMax) Then distXMax = distmm
'lato sinistro tl-bl
distmm = Math.Sqrt(Math.Pow(m_pworld(itl).X - m_pworld(ibl).X, 2) + Math.Pow(m_pworld(itl).Y - m_pworld(ibl).Y, 2))
distpix = Math.Sqrt(Math.Pow(m_psrc(itl).X - m_psrc(ibl).X, 2) + Math.Pow(m_psrc(itl).Y - m_psrc(ibl).Y, 2))
If (distpix / distmm > mm2pix) Then mm2pix = distpix / distmm
distYMax = distmm
'lato destro tr-br
distmm = Math.Sqrt(Math.Pow(m_pworld(itr).X - m_pworld(ibr).X, 2) + Math.Pow(m_pworld(itr).Y - m_pworld(ibr).Y, 2))
distpix = Math.Sqrt(Math.Pow(m_psrc(itr).X - m_psrc(ibr).X, 2) + Math.Pow(m_psrc(itr).Y - m_psrc(ibr).Y, 2))
If (distpix / distmm > mm2pix) Then mm2pix = distpix / distmm
If (distmm > distYMax) Then distYMax = distmm
' -- verifico che l'immagine non sia troppo grande
Dim widthImagePix As Double = (distXMax + m_ExtXL_mm + m_ExtXR_mm) * mm2pix
If widthImagePix > m_widthImagePixMax Then
' ???
mm2pix = mm2pix * CDbl(m_widthImagePixMax) / widthImagePix
End If
' allora la nostra nuova bitmap sarà:
m_dim_XProsp = Convert.ToInt16(distXMax * mm2pix)
m_dim_YProsp = Convert.ToInt16(distYMax * mm2pix)
m_mm2PixelProspZ0 = mm2pix
' ricavo i valori di estesnione dell'immagine in px
m_ExtXL_pix = Convert.ToInt16(m_ExtXL_mm * m_mm2PixelProspZ0)
m_ExtXR_pix = Convert.ToInt16(m_ExtXR_mm * m_mm2PixelProspZ0)
m_ExtYT_pix = Convert.ToInt16(m_ExtYT_mm * m_mm2PixelProspZ0)
m_ExtYB_pix = Convert.ToInt16(m_ExtYB_mm * m_mm2PixelProspZ0)
' fisso l'origine nel punto in alto a sinistra
Dim Origmm As PointF = m_pworld(itl)
' distanza punto_1 (top-right) da Origine in X (itr=1)
m_pdst(itr).X = (m_pworld(itr).X - m_pworld(itl).X) * m_mm2PixelProspZ0
' distanza punto_1 da Origine in Y (itr=1)
m_pdst(itr).Y = -(m_pworld(itr).Y - m_pworld(itl).Y) * m_mm2PixelProspZ0
' distanza punto_3 (bottom-left) da Origine in X (ibl=3)
m_pdst(ibl).X = (m_pworld(ibl).X - m_pworld(itl).X) * m_mm2PixelProspZ0
' distanza punto_3 da Origine in Y (ibl=3)
m_pdst(ibl).Y = -(m_pworld(ibl).Y - m_pworld(itl).Y) * m_mm2PixelProspZ0
' distanza punto_2 (bottom-right) da Origine in X (ibl=3)
m_pdst(ibr).X = (m_pworld(ibr).X - m_pworld(itl).X) * m_mm2PixelProspZ0
' distanza punto_2 (bottom-right) da Origine in Y (ibl=3)
m_pdst(ibr).Y = -(m_pworld(ibr).Y - m_pworld(itl).Y) * m_mm2PixelProspZ0
' distanza punto_0 (top-left) da Origine in X (itr=0), per definizione è l'origine stessa
m_pdst(itl).X = 0
' distanza punto_0 (top-left) da Origine in Y (itr=0), per definizione è l'origine stessa
m_pdst(itl).Y = 0
#If WinXP Then
m_MatDir = Emgu.CV.CameraCalibration.GetPerspectiveTransform(m_pdst, m_psrc) 'scambio dest e source!
#Else
' ottengo la matrice di correzione prospettica (di tipo EmguCV.Mat)
_perspMatDir = CvInvoke.GetPerspectiveTransform(m_pdst, m_psrc)
' unico modo che ho trovato per passare a mia matrice
Dim hh(8) As Double
_perspMatDir.CopyTo(Of Double)(hh)
For i = 0 To 2
For j = 0 To 2
m_MatDir(i, j) = hh(i * 3 + j)
Next
Next
#End If
m_Pos_x_z0_mm = m_pworld(ibl).X - m_ExtXL_mm
m_Pos_y_z0_mm = m_pworld(ibl).Y - m_ExtYB_mm
m_ProspCalibrated = True
End Sub
''' <summary>
''' Ottiene la matrice 'm_MatInv' per la correzione prospettica nel piano Z=0
''' </summary>
Private Sub CalcolaDatiCorrezioneInversa()
Dim i As Integer
For i = 0 To 3
m_pdst(i) = m_pworld(i)
Next
#If WinXP Then
m_MatInv = Emgu.CV.CameraCalibration.GetPerspectiveTransform(m_psrc, m_pdst)
#Else
Dim l_MatInv As New Emgu.CV.Mat(2, 3, CvEnum.DepthType.Cv64F, 1)
l_MatInv = CvInvoke.GetPerspectiveTransform(m_psrc, m_pdst)
' unico modo che ho trovato per passare a mia matrice
Dim hh(8) As Double
l_MatInv.CopyTo(Of Double)(hh)
For i = 0 To 2
For j As Integer = 0 To 2
m_MatInv(i, j) = hh(i * 3 + j)
Next
Next
#End If
End Sub
#End Region ' Calcolo matrici di correzione prospettica
' Crea file FinalImage.txt
Private Sub SaveDataImage(NomeFile As String)
CalcolaCorrezioniAltezza()
Dim writer As New StreamWriter(NomeFile)
writer.WriteLine("X = {0}", m_Pos_x_mm.ToString("F9", CultureInfo.InvariantCulture))
writer.WriteLine("Y = {0}", m_Pos_y_mm.ToString("F9", CultureInfo.InvariantCulture))
writer.WriteLine("X_ScaleCenter = {0}", m_scale_center.x.ToString("F9", CultureInfo.InvariantCulture))
writer.WriteLine("Y_ScaleCenter = {0}", m_scale_center.y.ToString("F9", CultureInfo.InvariantCulture))
writer.WriteLine("Pixelxmm = {0}", m_mm2PixelProspFinal.ToString("F9", CultureInfo.InvariantCulture))
writer.WriteLine("Z_Lastra = {0}", m_SpessLastra.ToString("F9", CultureInfo.InvariantCulture))
writer.WriteLine("Z_scalexmm = {0}", m_fscalaxmm.ToString("F14", CultureInfo.InvariantCulture))
writer.WriteLine("Z_ScaleCenter = {0}", m_scale_centerZ.ToString("F9", CultureInfo.InvariantCulture))
writer.WriteLine("Z_Cali = {0}", m_ZCali.ToString("F9", CultureInfo.InvariantCulture))
writer.Close()
End Sub
Public Sub CorrezioneCompleta(Optional rEvents As Boolean = True)
Try
m_UndistImage = Nothing
Console.WriteLine("RICHIESTA CORREZIONE DISTORSIONE: " & MainModule.IndexProc)
' Correzione distorsione
Correggi()
If rEvents Then RaiseEvent FineCorrezioneLente()
Console.WriteLine("RICHIESTA CORREZIONE PROSPETTICA: " & MainModule.IndexProc)
CorreggiProspettiva(SpessLastra)
If rEvents Then RaiseEvent FineCorrezioneProspettiva()
Catch ex As Exception
RaiseEvent ProcessAborted(-1)
End Try
End Sub
Private Sub CalcolaMatriceCorrezioneProspettiva()
Dim ix As Integer, iy As Integer
Dim px As Single, py As Single
Dim m00 As Double, m01 As Double, m02 As Double
Dim m10 As Double, m11 As Double, m12 As Double
Dim m20 As Double, m21 As Double, m22 As Double
Dim m01iy As Double, m11iy As Double, m21iy As Double
Try
If m_UndistImage Is Nothing Then Return
m_dimx = m_UndistImage.Width
m_dimy = m_UndistImage.Height
CalcolaDatiCorrezioneDiretta()
m_SpessLastra = SpessLastra
' correggo calcolando i pixel (con funzione opencv non riesco a estendere)
m00 = m_MatDir(0, 0) : m01 = m_MatDir(0, 1) : m02 = m_MatDir(0, 2)
m10 = m_MatDir(1, 0) : m11 = m_MatDir(1, 1) : m12 = m_MatDir(1, 2)
m20 = m_MatDir(2, 0) : m21 = m_MatDir(2, 1) : m22 = m_MatDir(2, 2)
m_dim_XProspExt = m_dim_XProsp + m_ExtXL_pix + m_ExtXR_pix
m_dim_YProspExt = m_dim_YProsp + m_ExtYT_pix + m_ExtYB_pix
ReDim MatConvP(m_dim_XProspExt, m_dim_YProspExt)
For iy = 0 To m_dim_YProspExt - 1
Dim iy2 As Integer = iy - m_ExtYT_pix
m01iy = m01 * iy2
m11iy = m11 * iy2
m21iy = m21 * iy2
For ix = 0 To m_dim_XProspExt - 1
Dim ix2 As Short = ix - m_ExtXL_pix
px = (m00 * ix2 + m01iy + m02) / (m20 * ix2 + m21iy + m22)
py = (m10 * ix2 + m11iy + m12) / (m20 * ix2 + m21iy + m22)
MatConvP(ix, iy) = New clPuntoPix
If px >= 0 And px < m_dimx And py >= 0 AndAlso py < m_dimy Then
MatConvP(ix, iy).X = px
MatConvP(ix, iy).Y = py
Else
MatConvP(ix, iy).X = -1
MatConvP(ix, iy).Y = -1
End If
Next
Next
m_bMatProspOk = True
Catch ex As Exception
m_bMatProspOk = False
Throw New Exception(ex.Message)
End Try
End Sub
Private Sub CorreggiProspettivaDaMatriceOCV(spessLastra As Double)
Console.WriteLine("INIZIO CREAZIONE IMMAGINE CON CORREZIONE OCV: " & MainModule.IndexProc)
Dim flags As Integer = Emgu.CV.CvEnum.Inter.Linear
Dim fillVal As New MCvScalar(0, 0, 0, 0)
Dim dstImage As New Image(Of Emgu.CV.Structure.Rgb, Byte)(m_dim_XProspExt, m_dim_YProspExt)
Emgu.CV.CvInvoke.Remap(New Image(Of Emgu.CV.Structure.Rgb, Byte)(m_UndistImage), dstImage, _ocvMapx, _ocvMapy, flags, BorderType.Default)
m_FinalImage = dstImage.Bitmap
SaveBitmap(m_FinalImage, SaveDir & "FinalImage.jpg")
Console.WriteLine("FINE CREAZIONE IMMAGINE CON CORREZIONE OCV: " & MainModule.IndexProc)
SaveDataImage(SaveDir & "FinalImage.txt")
End Sub
Private Shared Function GetEncoderInfo(ByVal mimeType As String) As ImageCodecInfo
' Get image codecs for all image formats
Dim codecs As ImageCodecInfo() = ImageCodecInfo.GetImageEncoders()
' Find the correct image codec
For i As Integer = 0 To codecs.Length - 1
If (codecs(i).MimeType = mimeType) Then
Return codecs(i)
End If
Next i
Return Nothing
End Function
Private Sub CalcolaMatriceOCV()
Dim ix As Integer, iy As Integer
_ocvMapx = New Matrix(Of Single)(m_dim_YProspExt, m_dim_XProspExt)
_ocvMapy = New Matrix(Of Single)(m_dim_YProspExt, m_dim_XProspExt)
For iy = 0 To m_dim_YProspExt - 1
For ix = 0 To (m_dim_XProspExt - 1)
_ocvMapx(iy, ix) = MatConvP(ix, iy).X
_ocvMapy(iy, ix) = MatConvP(ix, iy).Y
Next
Next
End Sub
Private Sub CalcolaCorrezioniAltezza()
' fattore di scala data la nuova altezza
Dim fattScala As Double
m_SpessCorr = m_SpessLastra - m_ZCali
fattScala = Pow(m_fscalaxmm, m_SpessCorr)
m_mm2PixelProspFinal = m_mm2PixelProspZ0 / fattScala
m_Pos_x_mm = m_Pos_x_z0_mm - m_scale_center.x
m_Pos_y_mm = m_Pos_y_z0_mm - m_scale_center.y
m_Pos_x_mm = m_Pos_x_mm * fattScala
m_Pos_y_mm = m_Pos_y_mm * fattScala
m_Pos_x_mm = m_Pos_x_mm + m_scale_center.x
m_Pos_y_mm = m_Pos_y_mm + m_scale_center.y
End Sub
Public Sub SaveClickMsg(numerr As Integer)
Dim NomeFile As String
Dim nf As Integer
NomeFile = SaveDir & "click.txt"
nf = FreeFile()
FileOpen(nf, NomeFile, OpenMode.Output)
Print(nf, "Err=" & numerr.ToString)
FileClose(nf)
End Sub
' questa è la correzione inversa a quello che mi serve...
Public Function CorreggiPunto(p As Point) As Point
Dim po As Point
po.X = MatConvP(p.X, p.Y).X
po.Y = MatConvP(p.X, p.Y).Y
Return po
End Function
#End Region
Public Sub FreeImages()
If m_UndistImage IsNot Nothing Then m_UndistImage.Dispose()
m_UndistImage = Nothing
If m_FinalImage IsNot Nothing Then m_FinalImage.Dispose()
m_FinalImage = Nothing
If m_InputImage IsNot Nothing Then m_InputImage.Dispose()
m_InputImage = Nothing
End Sub
#Region "Conversioni da mm a pixel e viceversa su Img già raddrizzata"
Public Sub MM2PixOnUndist(pmm As PointF, ByRef ppx As PointF)
If _thprocess IsNot Nothing AndAlso _thprocess.IsAlive Then Return
CalcolaCorrezioniAltezza()
ppx.X = (pmm.X - m_Pos_x_mm) * m_mm2PixelProspFinal
ppx.Y = m_FinalImage.Height - (pmm.Y - m_Pos_y_mm) * m_mm2PixelProspFinal
End Sub
Public Sub Pix2MMOnUndist(ppx As PointF, ByRef pmm As PointF)
If _thprocess IsNot Nothing AndAlso _thprocess.IsAlive Then Return
CalcolaCorrezioniAltezza()
pmm.X = ppx.X / m_mm2PixelProspFinal + m_Pos_x_mm
If m_FinalImage IsNot Nothing Then
pmm.Y = (m_FinalImage.Height - ppx.Y) / m_mm2PixelProspFinal + m_Pos_y_mm
End If
End Sub
Public Function SaveModelFromRectangle(FileName As String, xLeft As Double, yTop As Double, xRight As Double, yBottom As Double)
Try
If FinalImage Is Nothing Then Return False
Dim cvimage As New Image(Of Emgu.CV.Structure.Bgr, Byte)(FinalImage)
Dim x1 As Integer = Math.Min(xLeft, xRight)
Dim y1 As Integer = Math.Min(yTop, yBottom)
Dim w As Integer = Math.Abs(xRight - xLeft)
Dim h As Integer = Math.Abs(yBottom - yTop)
Dim rmodel As New Rectangle(x1, y1, w, h)
cvimage.ROI = rmodel
cvimage.Save(FileName)
Return True
Catch ex As Exception
Return False
End Try
End Function
#End Region
End Class