blob: 356c0d621bad21ad6ea3f7980c52f7fe8bbe708f [file] [log] [blame]
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""This module provides implementations of common computer Vision operations."""
from __future__ import division
from telemetry.internal.util import external_modules
np = external_modules.ImportRequiredModule('numpy')
def AreLinesOrthogonal(line1, line2, tolerance):
"""Returns true if lines are within tolerance radians of being orthogonal."""
# Map each line onto an angle between 0 and 180.
theta1 = np.arctan2(np.float(line1[1] - line1[3]),
np.float(line1[0] - line1[2]))
theta2 = np.arctan2(np.float(line2[1] - line2[3]),
np.float(line2[0] - line2[2]))
angle2 = abs(theta2 - theta1)
if angle2 >= np.pi:
angle2 -= np.pi
# If the difference between the angles is more than pi/2 - tolerance, the
# lines are not orthogonal.
return not abs(angle2 - (np.pi / 2.0)) > tolerance
def FindLineIntersection(line1, line2):
"""If the line segments intersect, returns True and their intersection.
Otherwise, returns False and the intersection of the line segments if they
were to be extended."""
# Compute g, and h, the factor by which each line must be extended to
# exactly touch the other line. If both are between 0 and 1, then the lines
# currently intersect. We use h to compute their intersection.
line1p1 = line1[:2]
line1p0 = line1[2:]
line2p1 = line2[:2]
line2p0 = line2[2:]
E = np.subtract(line1p1, line1p0)
F = np.subtract(line2p1, line2p0)
Pe = np.asfarray((-E[1], E[0]))
Pf = np.asfarray((-F[1], F[0]))
h = np.dot(np.subtract(line1p0, line2p0), Pe)
h = np.divide(h, np.dot(F, Pe))
g = np.dot(np.subtract(line2p0, line1p0), Pf)
g = np.divide(g, np.dot(E, Pf))
intersection = np.add(line2p0, np.dot(F, h))
intersect = (h >= -0.000001 and h <= 1.000001 and
g >= -0.000001 and g <= 1.000001)
return intersect, intersection
def ExtendLines(lines, length):
"""Extends lines in an array to a given length, maintaining the center
point. Does not necessarily maintain point order."""
half_length = length / 2.0
angles = np.arctan2(lines[:, 1] - lines[:, 3], lines[:, 0] - lines[:, 2])
xoffsets = half_length * np.cos(angles)
yoffsets = half_length * np.sin(angles)
centerx = (lines[:, 0] + lines[:, 2]) / 2.0
centery = (lines[:, 1] + lines[:, 3]) / 2.0
lines[:, 0] = centerx - xoffsets
lines[:, 2] = centerx + xoffsets
lines[:, 1] = centery - yoffsets
lines[:, 3] = centery + yoffsets
return lines
def IsPointApproxOnLine(point, line, tolerance=1):
"""Approximates distance between point and line for small distances using
the determinant and checks whether it's within the tolerance. Tolerance is
an approximate distance in pixels, precision decreases with distance."""
xd = line[0] - line[2]
yd = line[1] - line[3]
det = ((xd) * (point[1] - line[3])) - ((yd) * (point[0] - line[2]))
tolerance = float(tolerance) * (abs(xd) + abs(yd))
return abs(det) * 2.0 <= tolerance
def SqDistances(points1, points2):
"""Computes the square of the distance between two sets of points, or a
set of points and a point."""
d = np.square(points1 - points2)
return d[:, 0] + d[:, 1]
def SqDistance(point1, point2):
"""Computes the square of the distance between two points."""
d = np.square(point1 - point2)
return d[0] + d[1]