Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
MPAI-Private
MPAI-CAE
arp
Video Analyzer
Commits
864f7f04
Commit
864f7f04
authored
Apr 30, 2023
by
Matteo
Browse files
update
parent
b89f3469
Changes
24
Hide whitespace changes
Inline
Side-by-side
src/utility.cpp
0 → 100644
View file @
864f7f04
#include
"utility.h"
using
namespace
cv
;
using
namespace
std
;
void
utility
::
detectShape
(
Ptr
<
GeneralizedHoughGuil
>
alg
,
Mat
templateShape
,
int
posThresh
,
vector
<
Vec4f
>
&
positivePositions
,
Mat
&
positiveVotes
,
vector
<
Vec4f
>
&
negativePositions
,
Mat
&
negativeVotes
,
Mat
processingArea
)
{
alg
->
setPosThresh
(
posThresh
);
alg
->
setTemplate
(
templateShape
);
int
oldSizePositive
=
0
;
int
i
=
0
;
int
maxVote
=
0
;
// Process shapes with positive angles
alg
->
setMinAngle
(
0
);
alg
->
setMaxAngle
(
3
);
while
(
true
)
{
alg
->
detect
(
processingArea
,
positivePositions
,
positiveVotes
);
int
currentSize
=
positivePositions
.
size
();
if
(
currentSize
==
1
)
{
// We detected the most interesting shape
break
;
}
else
if
(
currentSize
==
0
&&
oldSizePositive
>
0
)
{
// It is not possible to detect only one shape with the current parameters
alg
->
setPosThresh
(
posThresh
+
i
-
1
);
// Decrease position value
alg
->
detect
(
processingArea
,
positivePositions
,
positiveVotes
);
// Detect all available shapes
break
;
}
else
if
(
currentSize
==
0
&&
oldSizePositive
==
0
)
{
// Impossible to find with these parameters
break
;
}
oldSizePositive
=
currentSize
;
// Find maximum vote
for
(
int
j
=
0
;
j
<
positiveVotes
.
cols
/
3
;
j
++
)
{
if
(
positiveVotes
.
at
<
int
>
(
3
*
j
)
>
maxVote
)
maxVote
=
positiveVotes
.
at
<
int
>
(
3
*
j
);
}
if
(
currentSize
>
10
)
{
i
+=
5
;
// To speed up computation when there are too many matches
}
else
if
(
maxVote
-
(
posThresh
+
i
)
>
100
)
{
i
+=
100
;
// To speed up computation when there are few super high matches
}
else
{
i
++
;
}
alg
->
setPosThresh
(
posThresh
+
i
);
}
int
oldSizeNegative
=
0
;
// Reset incremental position value
i
=
0
;
maxVote
=
0
;
// Process shapes with negative angles
alg
->
setMinAngle
(
357
);
alg
->
setMaxAngle
(
360
);
while
(
true
)
{
alg
->
detect
(
processingArea
,
negativePositions
,
negativeVotes
);
int
currentSize
=
negativePositions
.
size
();
if
(
currentSize
==
1
)
{
// We detected the most interesting shape
break
;
}
else
if
(
currentSize
==
0
&&
oldSizeNegative
>
0
)
{
// It is not possible to detect only one shape with the current parameters
alg
->
setPosThresh
(
posThresh
+
i
-
1
);
// Decrease position value
alg
->
detect
(
processingArea
,
negativePositions
,
negativeVotes
);
// Detect all available shapes
break
;
}
else
if
(
currentSize
==
0
&&
oldSizeNegative
==
0
)
{
// Impossible to found with these parameters
break
;
}
oldSizeNegative
=
currentSize
;
// Find maximum vote
for
(
int
j
=
0
;
j
<
positiveVotes
.
cols
/
3
;
j
++
)
{
if
(
positiveVotes
.
at
<
int
>
(
3
*
j
)
>
maxVote
)
maxVote
=
positiveVotes
.
at
<
int
>
(
3
*
j
);
}
if
(
currentSize
>
10
)
{
i
+=
5
;
// To speed up computation when there are too many matches
}
else
if
(
maxVote
-
(
posThresh
+
i
)
>
100
)
{
i
+=
100
;
// To speed up computation when there are few super high matches
}
else
{
i
++
;
}
alg
->
setPosThresh
(
posThresh
+
i
);
}
}
RotatedRect
utility
::
drawShapes
(
Mat
frame
,
Vec4f
&
positions
,
Scalar
color
,
int
width
,
int
height
,
int
offsetX
,
int
offsetY
,
float
processingScale
)
{
RotatedRect
rr
;
Point2f
rrpts
[
4
];
Point2f
pos
(
positions
[
0
]
+
offsetX
,
positions
[
1
]
+
offsetY
);
float
scale
=
positions
[
2
];
float
angle
=
positions
[
3
];
rr
.
center
=
pos
*
processingScale
;
rr
.
size
=
Size2f
(
width
*
scale
*
processingScale
,
height
*
scale
*
processingScale
);
rr
.
angle
=
angle
;
rr
.
points
(
rrpts
);
line
(
frame
,
rrpts
[
0
],
rrpts
[
1
],
color
,
2
);
line
(
frame
,
rrpts
[
1
],
rrpts
[
2
],
color
,
2
);
line
(
frame
,
rrpts
[
2
],
rrpts
[
3
],
color
,
2
);
line
(
frame
,
rrpts
[
3
],
rrpts
[
0
],
color
,
2
);
return
rr
;
}
void
utility
::
separateFrame
(
cv
::
Mat
frame
,
cv
::
Mat
&
odd_frame
,
cv
::
Mat
&
even_frame
)
{
int
i_odd_frame
=
0
;
int
i_even_frame
=
0
;
for
(
int
i
=
0
;
i
<
frame
.
rows
;
i
++
)
{
for
(
int
j
=
0
;
j
<
frame
.
cols
;
j
++
)
{
if
(
i
%
2
==
0
)
{
even_frame
.
at
<
cv
::
Vec3b
>
(
i_even_frame
,
j
)[
0
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
];
even_frame
.
at
<
cv
::
Vec3b
>
(
i_even_frame
,
j
)[
1
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
1
];
even_frame
.
at
<
cv
::
Vec3b
>
(
i_even_frame
,
j
)[
2
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
2
];
}
else
{
odd_frame
.
at
<
cv
::
Vec3b
>
(
i_odd_frame
,
j
)[
0
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
];
odd_frame
.
at
<
cv
::
Vec3b
>
(
i_odd_frame
,
j
)[
1
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
1
];
odd_frame
.
at
<
cv
::
Vec3b
>
(
i_odd_frame
,
j
)[
2
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
2
];
}
}
if
(
i
%
2
==
0
)
{
i_even_frame
++
;
}
else
{
i_odd_frame
++
;
}
}
return
;
}
cv
::
Mat
utility
::
difference
(
cv
::
Mat
&
prevFrame
,
cv
::
Mat
&
currentFrame
)
{
cv
::
Mat
diff
=
currentFrame
.
clone
();
for
(
int
i
=
0
;
i
<
currentFrame
.
rows
;
i
++
)
{
for
(
int
j
=
0
;
j
<
currentFrame
.
cols
;
j
++
)
{
if
(
prevFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
]
!=
currentFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
]
||
prevFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
1
]
!=
currentFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
1
]
||
prevFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
2
]
!=
currentFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
2
])
{
// Different pixels
diff
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
]
=
0
;
}
else
{
// Identical pixels
diff
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
]
=
255
;
}
}
}
return
diff
;
}
\ No newline at end of file
src/utility.h
View file @
864f7f04
#include
<opencv2/core/core.hpp>
#include
<opencv2/highgui/highgui.hpp>
#include
<opencv2/imgcodecs.hpp>
#include
<opencv2/imgproc.hpp>
using
namespace
cv
;
using
namespace
cv
;
using
namespace
std
;
using
namespace
std
;
namespace
fs
=
std
::
filesystem
;
namespace
fs
=
std
::
filesystem
;
/*************************************************************************************************/
namespace
utility
{
/*************************************** OpenCV FUNCTIONS ****************************************/
/*************************************************************************************************/
/**
* @brief Detects a given shape in an image, using a the OpenCV algorithm GeneralizedHoughGuil.
*
* @param[in] alg the algorithm instance;
* @param[in] templateShape the shape to detect;
* @param[in] posThresh the position votes threshold;
* @param[out] positivePositions vector representing the position assigned to each found rectangle for positive angles;
* @param[out] positiveVotes vector representing the vote assigned to each found rectangle for positive angles;
* @param[out] negativePositions vector representing the position assigned to each found rectangle for negative angles;
* @param[out] negativeVotes vector representing the vote assigned to each found rectangle for negative angles;
* @param[in] processingArea the image to be processed.
*/
void
detectShape
(
Ptr
<
GeneralizedHoughGuil
>
alg
,
Mat
templateShape
,
int
posThresh
,
vector
<
Vec4f
>
&
positivePositions
,
Mat
&
positiveVotes
,
vector
<
Vec4f
>
&
negativePositions
,
Mat
&
negativeVotes
,
Mat
processingArea
)
{
alg
->
setPosThresh
(
posThresh
);
alg
->
setTemplate
(
templateShape
);
int
oldSizePositive
=
0
;
int
i
=
0
;
int
maxVote
=
0
;
// Process shapes with positive angles
class
Frame
:
Mat
{
alg
->
setMinAngle
(
0
);
public:
alg
->
setMaxAngle
(
3
);
Frame
()
:
Mat
()
{}
while
(
true
)
{
Frame
(
const
Mat
&
m
)
:
Mat
(
m
)
{}
alg
->
detect
(
processingArea
,
positivePositions
,
positiveVotes
);
Frame
(
const
Frame
&
f
)
:
Mat
(
f
)
{}
int
currentSize
=
positivePositions
.
size
();
Frame
&
operator
=
(
const
Mat
&
m
)
{
if
(
currentSize
==
1
)
{
Mat
::
operator
=
(
m
);
// We detected the most interesting shape
return
*
this
;
break
;
}
else
if
(
currentSize
==
0
&&
oldSizePositive
>
0
)
{
// It is not possible to detect only one shape with the current parameters
alg
->
setPosThresh
(
posThresh
+
i
-
1
);
// Decrease position value
alg
->
detect
(
processingArea
,
positivePositions
,
positiveVotes
);
// Detect all available shapes
break
;
}
else
if
(
currentSize
==
0
&&
oldSizePositive
==
0
)
{
// Impossible to find with these parameters
break
;
}
}
oldSizePositive
=
currentSize
;
Frame
&
operator
=
(
const
Frame
&
f
)
{
// Find maximum vote
Mat
::
operator
=
(
f
);
for
(
int
j
=
0
;
j
<
positiveVotes
.
cols
/
3
;
j
++
)
{
return
*
this
;
if
(
positiveVotes
.
at
<
int
>
(
3
*
j
)
>
maxVote
)
maxVote
=
positiveVotes
.
at
<
int
>
(
3
*
j
);
}
}
Frame
clone
()
const
{
if
(
currentSize
>
10
)
{
return
Frame
(
Mat
::
clone
());
i
+=
5
;
// To speed up computation when there are too many matches
}
else
if
(
maxVote
-
(
posThresh
+
i
)
>
100
)
{
i
+=
100
;
// To speed up computation when there are few super high matches
}
else
{
i
++
;
}
alg
->
setPosThresh
(
posThresh
+
i
);
}
int
oldSizeNegative
=
0
;
// Reset incremental position value
i
=
0
;
maxVote
=
0
;
// Process shapes with negative angles
alg
->
setMinAngle
(
357
);
alg
->
setMaxAngle
(
360
);
while
(
true
)
{
alg
->
detect
(
processingArea
,
negativePositions
,
negativeVotes
);
int
currentSize
=
negativePositions
.
size
();
if
(
currentSize
==
1
)
{
// We detected the most interesting shape
break
;
}
else
if
(
currentSize
==
0
&&
oldSizeNegative
>
0
)
{
// It is not possible to detect only one shape with the current parameters
alg
->
setPosThresh
(
posThresh
+
i
-
1
);
// Decrease position value
alg
->
detect
(
processingArea
,
negativePositions
,
negativeVotes
);
// Detect all available shapes
break
;
}
else
if
(
currentSize
==
0
&&
oldSizeNegative
==
0
)
{
// Impossible to found with these parameters
break
;
}
}
oldSizeNegative
=
currentSize
;
Frame
&
downsample
(
int
factor
)
{
pyrDown
(
*
this
,
*
this
,
Size
(
size
().
width
/
factor
,
size
().
height
/
factor
));
// Find maximum vote
return
*
this
;
for
(
int
j
=
0
;
j
<
positiveVotes
.
cols
/
3
;
j
++
)
{
if
(
positiveVotes
.
at
<
int
>
(
3
*
j
)
>
maxVote
)
maxVote
=
positiveVotes
.
at
<
int
>
(
3
*
j
);
}
if
(
currentSize
>
10
)
{
i
+=
5
;
// To speed up computation when there are too many matches
}
else
if
(
maxVote
-
(
posThresh
+
i
)
>
100
)
{
i
+=
100
;
// To speed up computation when there are few super high matches
}
else
{
i
++
;
}
alg
->
setPosThresh
(
posThresh
+
i
);
}
}
/**
* @brief Draw rectangles on an image.
*
* @param frame Frame on which the rectangles will be drawn;
* @param positions The position of the rectangle;
* @param color The color of the rectangle;
* @param width The width of the rectangle;
* @param height The height of the rectangle;
* @param offsetX X offset on the position of the rectangle;
* @param offsetY Y offset on the position of the rectangle;
* @param processingScale Scaling factor, useful for downsizing.
* @return RotatedRect Object representing the drawn rectangle.
*/
RotatedRect
drawShapes
(
Mat
frame
,
Vec4f
&
positions
,
Scalar
color
,
int
width
,
int
height
,
int
offsetX
,
int
offsetY
,
float
processingScale
)
{
RotatedRect
rr
;
Point2f
rrpts
[
4
];
Point2f
pos
(
positions
[
0
]
+
offsetX
,
positions
[
1
]
+
offsetY
);
float
scale
=
positions
[
2
];
float
angle
=
positions
[
3
];
rr
.
center
=
pos
*
processingScale
;
rr
.
size
=
Size2f
(
width
*
scale
*
processingScale
,
height
*
scale
*
processingScale
);
rr
.
angle
=
angle
;
rr
.
points
(
rrpts
);
line
(
frame
,
rrpts
[
0
],
rrpts
[
1
],
color
,
2
);
line
(
frame
,
rrpts
[
1
],
rrpts
[
2
],
color
,
2
);
line
(
frame
,
rrpts
[
2
],
rrpts
[
3
],
color
,
2
);
line
(
frame
,
rrpts
[
3
],
rrpts
[
0
],
color
,
2
);
return
rr
;
}
/**
* @brief Function to deinterlace the current image.
*
* @param[in] frame image to be processed;
* @param[out] odd_frame odd plane;
* @param[out] even_frame even plane.
*/
void
separateFrame
(
cv
::
Mat
frame
,
cv
::
Mat
&
odd_frame
,
cv
::
Mat
&
even_frame
)
{
int
i_odd_frame
=
0
;
int
i_even_frame
=
0
;
for
(
int
i
=
0
;
i
<
frame
.
rows
;
i
++
)
{
for
(
int
j
=
0
;
j
<
frame
.
cols
;
j
++
)
{
if
(
i
%
2
==
0
)
{
even_frame
.
at
<
cv
::
Vec3b
>
(
i_even_frame
,
j
)[
0
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
];
even_frame
.
at
<
cv
::
Vec3b
>
(
i_even_frame
,
j
)[
1
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
1
];
even_frame
.
at
<
cv
::
Vec3b
>
(
i_even_frame
,
j
)[
2
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
2
];
}
else
{
odd_frame
.
at
<
cv
::
Vec3b
>
(
i_odd_frame
,
j
)[
0
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
];
odd_frame
.
at
<
cv
::
Vec3b
>
(
i_odd_frame
,
j
)[
1
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
1
];
odd_frame
.
at
<
cv
::
Vec3b
>
(
i_odd_frame
,
j
)[
2
]
=
frame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
2
];
}
}
}
Frame
&
convertColor
(
int
code
)
{
if
(
i
%
2
==
0
)
{
cv
::
cvtColor
(
*
this
,
*
this
,
code
);
i_even_frame
++
;
return
*
this
;
}
else
{
i_odd_frame
++
;
}
}
}
};
return
;
/**
* @brief Detects a given shape in an image, using a the OpenCV algorithm GeneralizedHoughGuil.
*
* @param[in] alg the algorithm instance;
* @param[in] templateShape the shape to detect;
* @param[in] posThresh the position votes threshold;
* @param[out] positivePositions vector representing the position assigned to each found rectangle for positive angles;
* @param[out] positiveVotes vector representing the vote assigned to each found rectangle for positive angles;
* @param[out] negativePositions vector representing the position assigned to each found rectangle for negative angles;
* @param[out] negativeVotes vector representing the vote assigned to each found rectangle for negative angles;
* @param[in] processingArea the image to be processed.
*/
void
detectShape
(
Ptr
<
GeneralizedHoughGuil
>
alg
,
Mat
templateShape
,
int
posThresh
,
vector
<
Vec4f
>
&
positivePositions
,
Mat
&
positiveVotes
,
vector
<
Vec4f
>
&
negativePositions
,
Mat
&
negativeVotes
,
Mat
processingArea
);
/**
* @brief Draw rectangles on an image.
*
* @param frame Frame on which the rectangles will be drawn;
* @param positions The position of the rectangle;
* @param color The color of the rectangle;
* @param width The width of the rectangle;
* @param height The height of the rectangle;
* @param offsetX X offset on the position of the rectangle;
* @param offsetY Y offset on the position of the rectangle;
* @param processingScale Scaling factor, useful for downsizing.
* @return RotatedRect Object representing the drawn rectangle.
*/
RotatedRect
drawShapes
(
Mat
frame
,
Vec4f
&
positions
,
Scalar
color
,
int
width
,
int
height
,
int
offsetX
,
int
offsetY
,
float
processingScale
);
/**
* @brief Function to deinterlace the current image.
*
* @param[in] frame image to be processed;
* @param[out] odd_frame odd plane;
* @param[out] even_frame even plane.
*/
void
separateFrame
(
cv
::
Mat
frame
,
cv
::
Mat
&
odd_frame
,
cv
::
Mat
&
even_frame
);
/**
* @brief Compute the number of different pixels between two frames.
*
* @param prevFrame the first frame;
* @param currentFrame the second frame.
* @return cv::Mat A black and white frame, where black pixels represent a difference, while white pixels represent an equality.
*/
cv
::
Mat
difference
(
cv
::
Mat
&
prevFrame
,
cv
::
Mat
&
currentFrame
);
}
}
/**
* @brief Compute the number of different pixels between two frames.
*
* @param prevFrame the first frame;
* @param currentFrame the second frame.
* @return cv::Mat A black and white frame, where black pixels represent a difference, while white pixels represent an equality.
*/
cv
::
Mat
difference
(
cv
::
Mat
&
prevFrame
,
cv
::
Mat
&
currentFrame
)
{
cv
::
Mat
diff
=
currentFrame
.
clone
();
for
(
int
i
=
0
;
i
<
currentFrame
.
rows
;
i
++
)
{
for
(
int
j
=
0
;
j
<
currentFrame
.
cols
;
j
++
)
{
if
(
prevFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
]
!=
currentFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
]
||
prevFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
1
]
!=
currentFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
1
]
||
prevFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
2
]
!=
currentFrame
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
2
])
{
// Different pixels
diff
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
]
=
0
;
}
else
{
// Identical pixels
diff
.
at
<
cv
::
Vec3b
>
(
i
,
j
)[
0
]
=
255
;
}
}
}
return
diff
;
}
\ No newline at end of file
tests/enums_test.cpp
0 → 100644
View file @
864f7f04
#include
<gtest/gtest.h>
#include
<boost/uuid/uuid.hpp>
#include
<boost/uuid/uuid_generators.hpp>
#include
"../src/lib/enums.h"
TEST
(
IrregularityType
,
toString
)
{
EXPECT_EQ
(
irregularityTypeToString
(
IrregularityType
::
WOW_AND_FLUTTER
),
"wf"
);
}
TEST
(
IrregularityType
,
fromString
)
{
EXPECT_EQ
(
irregularityTypeFromString
(
"wf"
),
IrregularityType
::
WOW_AND_FLUTTER
);
EXPECT_THROW
(
irregularityTypeFromString
(
"not_exists"
),
std
::
invalid_argument
);
}
tests/irregularity_test.cpp
0 → 100644
View file @
864f7f04
#include
<gtest/gtest.h>
#include
<boost/uuid/uuid.hpp>
#include
<boost/uuid/uuid_generators.hpp>
#include
"../src/lib/Irregularity.h"
TEST
(
Irregularity
,
Init
)
{
Irregularity
irreg
=
Irregularity
(
Source
::
Video
,
"00:00:00.000"
,
IrregularityType
::
WOW_AND_FLUTTER
,
"https://example.com/image.png"
);
Irregularity
irreg2
=
Irregularity
(
Source
::
Video
,
"00:00:00.000"
,
IrregularityType
::
WOW_AND_FLUTTER
,
"https://example.com/image.png"
);
EXPECT_NE
(
irreg
.
id
,
irreg2
.
id
);
EXPECT_EQ
(
irreg
.
source
,
irreg2
.
source
);
EXPECT_EQ
(
irreg
.
time_label
,
irreg2
.
time_label
);
EXPECT_EQ
(
irreg
.
type
,
irreg2
.
type
);
EXPECT_EQ
(
irreg
.
image_URI
,
irreg2
.
image_URI
);
}
Prev
1
2
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment