Esempio n. 1
0
    def _save_parameters(self):
        """finds the important parameters of the fitted ellipse

        Theory taken form http://mathworld.wolfram
        Args
        -----
        coef (list): list of the coefficients describing an ellipse
           [a,b,c,d,f,g] corresponding to ax**2+2bxy+cy**2+2dx+2fy+g
        Returns
        _______
        center (List): of the form [x0, y0]
        width (float): major axis
        height (float): minor axis
        phi (float): rotation of major axis form the x-axis in radians
        """

        #eigenvectors are the coefficients of an ellipse in general form
        #a*x^2 + 2*b*x*y + c*y^2 + 2*d*x + 2*f*y + g = 0 [eqn. 15) from (**) or (***)
        a = self.coef[0, 0]
        b = self.coef[1, 0] / 2.
        c = self.coef[2, 0]
        d = self.coef[3, 0] / 2.
        f = self.coef[4, 0] / 2.
        g = self.coef[5, 0]

        if (a - c) == 0:
            return True

        #finding center of ellipse [eqn.19 and 20] from (**)
        x0 = (c * d - b * f) / (b**2. - a * c)
        y0 = (a * f - b * d) / (b**2. - a * c)

        #Find the semi-axes lengths [eqn. 21 and 22] from (**)
        numerator = 2 * (a * f * f + c * d * d + g * b * b - 2 * b * d * f -
                         a * c * g)
        denominator1 = (b * b - a * c) * ((c - a) * np.sqrt(1 + 4 * b * b /
                                                            ((a - c) *
                                                             (a - c))) -
                                          (c + a))
        denominator2 = (b * b - a * c) * ((a - c) * np.sqrt(1 + 4 * b * b /
                                                            ((a - c) *
                                                             (a - c))) -
                                          (c + a))
        width = np.sqrt(numerator / denominator1)
        height = np.sqrt(numerator / denominator2)

        phi = .5 * np.arctan((2. * b) / (a - c))

        self.center = [
            self.shape_processor.corners[0][0] + x0,
            self.shape_processor.corners[0][1] + y0
        ]
        self.width = width
        self.height = height
        self.dimensions_int = tuple_int((width, height))

        self.angle = np.rad2deg(phi) % 360
        return False
Esempio n. 2
0
    def arm(self, width, height, image):
        self.frame = 0
        self.dimensions = tuple_int((width * self.scale, height * self.scale))

        width, height = self.dimensions

        self.center = (width // 2, height // 2)

        self.resize(image)

        #image = self.rotate(image, self.ENGINE.angle)
        self.ENGINE.importer = self
        self.ENGINE.arm(width, height, image)
Esempio n. 3
0
    def arm(self, width, height, image):

        self.dimensions = tuple_int((width * self.scale, height * self.scale))

        width, height = self.dimensions

        self.center = (width // 2, height // 2)

        if self.scale == 1:
            self.resize = lambda x: x
        else:
            self.resize = self.resize_image

        self.resize(image)

        #image = self.rotate(image, self.ENGINE.angle)
        config.engine.arm(width, height, image)
Esempio n. 4
0
    def fit(self, x: np.ndarray, y: np.ndarray) -> bool:

        try:
            x_coord, y_coord, radius, v = self.hyper_fit(x, y)

            self.center = [
                self.shape_processor.corners[0][0] + x_coord,
                self.shape_processor.corners[0][1] + y_coord
            ]
            self.width = self.height = radius

            self.dimensions_int = tuple_int((radius, radius))

        except:
            return False

        return True
Esempio n. 5
0
    def track(self, last: bool = False):

        try:

            if config.engine.blink_i == 1:
                self.corners = self.standard_corners.copy()
                self.walkout_offset = 0
                self.refresh_source(self.source)
                contours, hierarchy = cv2.findContours(self.area, 1, 2)
                if len(contours) > 0:
                    dists = np.zeros(len(contours))
                    for i, cnt in enumerate(contours):

                        M = cv2.moments(cnt)
                        try:
                            cx = int(M['m10'] / M['m00'])
                            cy = int(M['m01'] / M['m00'])
                            if self.type == 1:
                                dists[i] = np.mean(self.source[cy - 2:cy + 2,
                                                               cx - 2:cx + 2])
                            else:

                                dists[i] = np.sqrt((cx - self.center[0])**2 +
                                                   (cy - self.center[1])**2)

                        except:
                            dists[i] = 255

                    from operator import itemgetter
                    #todo: score these based on 1) color and 2) distance to center
                    M = cv2.moments(contours[min(enumerate(dists),
                                                 key=itemgetter(1))[0]])
                    try:
                        cx = round(M['m10'] / M['m00'])
                        cy = round(M['m01'] / M['m00'])
                    except:

                        return False
                    #print(cx,cy)
                    self.center = (cx, cy)

                    #self.source[cy,cx]=250
                    #cv2.imshow("JJ", self.source)
                    #cv2.waitKey(0)

            center = [
                self.center[0] - self.corners[0][0],
                self.center[1] - self.corners[0][1]
            ]
            walkout = self.walkout
            walkout.reset(center)
            fit_product = 1
            if walkout.walkout():

                fit_product = self.fit_model

                if fit_product.fit(walkout.rx, walkout.ry):
                    ellipse = fit_product
                else:
                    ellipse = 0
            else:
                ellipse = 0

        except Exception as e:
            print(e)
            return False

        if ellipse == fit_product:

            center, width, height = ellipse.center, ellipse.width, ellipse.height
            if width * height > 4:

                # if self.type == 2:
                #     if distance(np.array(center), np.array(self.center)) > 6: #normalize qqqq
                #         self.center = self.original_center[self.center_index]
                #         self.corners        =   self.standard_corners.copy()
                #         return False

                self.ellipse = ellipse
                self.center = center

                #"walkout_offset" defines the walkout offset for the next frame.
                #The multiplication factor, here .4, returns slightly below the average.
                self.walkout_offset = int(.4 * (width + height))

                self.margin = np.amax(ellipse.dimensions_int) * 2
                center_int = tuple_int(center)

                self.corners[0] = (max(center_int[0] - self.margin,
                                       0), max(center_int[1] - self.margin, 0))
                self.corners[1] = (min(center_int[0] + self.margin,
                                       config.engine.width),
                                   min(center_int[1] + self.margin,
                                       config.engine.height))

                self.center_index = 0

                margin = to_int(np.amax(ellipse.dimensions_int) * 1)

                #self.bbox = (max(center_int[0] - margin, 0),  max(center_int[1] - margin, 0), margin * 2, margin * 2)

                # try:
                #     if self.bbox:
                #         (success, box) = self.tracker.update(self.source)
                #         if success:
                #             box=np.array(box, dtype=int)
                #             x,y,w,h = box
                #
                #             cv2.rectangle(self.source,(x,y),(x+w,y+h),(0,255,0),1)
                #             #cv2.rectangle(self.source, box, (0,255,0),1)
                #             cv2.imshow("Kk", self.source)
                #         #cv2.waitKey(0)
                #         #print(box)
                # except Exception as e:
                #     print(e)
                #     pass

                return True

        if last:
            return False
        #   Shape detection failed, try contour detection
        self.corners = self.standard_corners.copy()
        self.walkout_offset = 0
        self.refresh_source(self.source)
        contours, hierarchy = cv2.findContours(self.area, 1, 2)
        if len(contours) > 0:
            dists = np.zeros(len(contours))
            for i, cnt in enumerate(contours):

                M = cv2.moments(cnt)
                try:
                    cx = int(M['m10'] / M['m00'])
                    cy = int(M['m01'] / M['m00'])
                    if self.type == 1:
                        dists[i] = np.mean(self.source[cy - 2:cy + 2,
                                                       cx - 2:cx + 2])
                    else:

                        dists[i] = np.sqrt((cx - self.center[0])**2 +
                                           (cy - self.center[1])**2)

                except:
                    dists[i] = 255

            from operator import itemgetter
            #todo: score these based on 1) color and 2) distance to center
            M = cv2.moments(contours[min(enumerate(dists),
                                         key=itemgetter(1))[0]])
            try:
                cx = round(M['m10'] / M['m00'])
                cy = round(M['m01'] / M['m00'])
            except:

                return False
            #print(cx,cy)
            self.center = (cx, cy)
            return self.track(True)

        return False
Esempio n. 6
0
    def track(self):

        try:
            center = [
                self.center[0] - self.corners[0][0],
                self.center[1] - self.corners[0][1]
            ]
            walkout = self.walkout
            walkout.reset(center)
            fit_product = 1
            if walkout.walkout():

                fit_product = self.fit_model

                if fit_product.fit(walkout.rx, walkout.ry):
                    ellipse = fit_product
                else:
                    ellipse = 0
            else:
                ellipse = 0

        except Exception as e:
            return False

        if ellipse == fit_product:

            center, width, height = ellipse.center, ellipse.width, ellipse.height

            # if self.type == 2:
            #     if distance(np.array(center), np.array(self.center)) > 6: #normalize qqqq
            #         self.center = self.original_center[self.center_index]
            #         self.corners        =   self.standard_corners.copy()
            #         return False

            self.ellipse = ellipse
            self.center = center

            #"walkout_offset" defines the walkout offset for the next frame.
            #The multiplication factor, here .4, returns slightly below the average.
            self.walkout_offset = int(.4 * (width + height))

            self.margin = np.amax(ellipse.dimensions_int) * 2
            center_int = tuple_int(center)

            self.corners[0] = (max(center_int[0] - self.margin,
                                   0), max(center_int[1] - self.margin, 0))
            self.corners[1] = (min(center_int[0] + self.margin,
                                   self.ENGINE.width),
                               min(center_int[1] + self.margin,
                                   self.ENGINE.height))

            self.center_index = 0
            return True
        else:
            #   Shape detection failed. We reset the crop area and iterate through a list of alternative center points.
            print("B")
            self.center = self.original_center[
                self.
                center_index]  # This loops through a list with centers surrounding the origin.
            self.corners = self.standard_corners.copy()
            self.walkout_offset = 0

            if self.center_index < 8:
                self.center_index += 1
                self.track()
            else:
                self.center_index = 0
                return False
Esempio n. 7
0
    def cr_artifacts(self, cr_processor, offsetx: int, offsety: int,
                     pupil_area) -> None:
        """
        Computes pupillary overlaps and acts to remove these artifacts.
        """

        cr_center, cr_width, cr_height, cr_angle, cr_dimensions_int = cr_processor.ellipse.parameters(
        )

        cr_center_int = tuple_int(cr_center)
        larger_width, larger_height = larger_radius = tuple(
            int(1.2 * element) for element in cr_dimensions_int)

        cr_width_norm = larger_width * self.norm
        cr_height_norm = larger_height * self.norm

        dimensional_product = larger_width * larger_height

        arc = [
            dimensional_product /
            np.sqrt((cr_width_norm * anglesteps_cos[i])**2 +
                    (cr_width_norm * anglesteps_sin[i])**2)
            for i in angular_range
        ]
        cos_sin_arc = [(to_int(anglesteps_cos[i] * arc[i]),
                        to_int(anglesteps_sin[i] * arc[i]))
                       for i in angular_range]

        hit_list = zeros.copy()

        for i, arc_element in enumerate(cos_sin_arc):
            cos, sin = arc_element
            x = cr_center_int[0] + offsetx + cos
            y = cr_center_int[1] + offsety + sin
            n = 1
            strike = 0

            while n < self.norm_cr_artefact:  #normalize qqqq
                n += 1
                try:
                    if pupil_area[y, x] != 0:
                        hit_list[i] = i + 1
                        break
                    else:
                        x += cos
                        y += sin
                except:
                    break

        if np.any(hit_list):
            delta = np.count_nonzero(number_row - hit_list)

            if delta < self.norm_cr_artefact:

                cv2.ellipse(self.pupil_source, cr_center_int, larger_radius,
                            cr_angle, 0, 360, 0, -1)
            else:

                for element in hit_list:
                    if element != 0:
                        cos, sin = cos_sin_arc[element - 1]
                        x = cr_center_int[0] + cos
                        y = cr_center_int[1] + sin
                        cv2.ellipse(self.pupil_source, cr_center_int,
                                    larger_radius, cr_angle, element * 40 - 40,
                                    element * 40, 0, 4)  #normalize qqqq
Esempio n. 8
0
    def update_track(self, blink: int) -> None:
        frame_preview = cv2.cvtColor(config.engine.source, cv2.COLOR_GRAY2BGR)
        frame_source = frame_preview.copy()
        cr_width = pupil_width = -1
        Processor = self.pupil_processor
        if blink == 0:

            self.rplace_markers(frame_preview)
            for index, cr_processor in enumerate(config.engine.cr_processors):
                if cr_processor.active:

                    cr_corners = cr_processor.corners
                    cr_center, cr_width, cr_height, cr_angle, cr_dimensions_int = cr_processor.ellipse.parameters(
                    )

                    if self._state == "adjustment":
                        if cr_processor == self.current_cr_processor:
                            color = bluish
                        else:
                            color = green
                        try:

                            cv2.ellipse(frame_preview, tuple_int(cr_center),
                                        cr_dimensions_int, cr_angle, 0, 360,
                                        color, 1)
                            self.place_cross(frame_preview, cr_center, color)
                            cv2.rectangle(frame_preview, cr_corners[0],
                                          cr_corners[1], color)

                            cv2.putText(
                                frame_preview, "{}".format(index + 2),
                                (int((cr_corners[1][0] + cr_corners[0][0]) *
                                     .5 - 3), cr_corners[0][1] - 3), font, .7,
                                color, 0, cv2.LINE_4)
                        except Exception as e:
                            cr_processor.active = False

                    else:
                        self.place_cross(frame_preview, cr_center, bluish)

            try:

                pupil_corners = Processor.corners
                pupil_center, pupil_width, pupil_height, pupil_angle, pupil_dimensions_int = Processor.ellipse.parameters(
                )

                cv2.ellipse(frame_preview, tuple_int(pupil_center),
                            pupil_dimensions_int, pupil_angle, 0, 360, red, 1)
                self.place_cross(frame_preview, pupil_center, red)
                cv2.rectangle(frame_preview, pupil_corners[0],
                              pupil_corners[1], red)
            except:
                pass

        if self._state == "adjustment":
            stock_P = self.PStock.copy()
            stock_CR = self.CRStock.copy()

            if cr_width != -1:

                cr_area = self.current_cr_processor.area

                offset_y = int((self.binary_height - cr_area.shape[0]) / 2)
                offset_x = int((self.binary_width - cr_area.shape[1]) / 2)
                stock_CR[offset_y:min(offset_y +
                                      cr_area.shape[0], self.binary_height),
                         offset_x:min(offset_x + cr_area.shape[1], self.
                                      binary_width)] = cr_area
                stock_CR[0:20, 0:self.binary_width] = self.crstock_txt_selected
            else:
                stock_CR[0:20, 0:self.binary_width] = self.crstock_txt

            if pupil_width != -1:
                # stock_P[pcorners[0][1]:pcorners[0][1]+Processor.area.shape[0],
                # pcorners[0][0]:pcorners[0][0]+Processor.area.shape[1]] = Processor.area
                stock_P[0:20, 0:self.binary_width] = self.pstock_txt_selected

                pupil_area = Processor.area

                offset_y = int((self.binary_height - pupil_area.shape[0]) / 2)
                offset_x = int((self.binary_width - pupil_area.shape[1]) / 2)
                stock_P[offset_y:min(offset_y +
                                     pupil_area.shape[0], self.binary_height),
                        offset_x:min(offset_x + pupil_area.shape[1], self.
                                     binary_width)] = pupil_area

            else:
                stock_P[0:20, 0:self.binary_width] = self.pstock_txt

            cv2.putText(
                stock_P, "{} || {}".format(round(Processor.binarythreshold, 1),
                                           Processor.blur),
                (10, self.binary_height - 10), font, .7, 255, 0, cv2.LINE_4)
            cv2.putText(
                stock_CR, "{} || {}".format(
                    round(self.current_cr_processor.binarythreshold, 1),
                    self.current_cr_processor.blur),
                (10, self.binary_height - 10), font, .7, 255, 0, cv2.LINE_4)

            frame_source[0:20, 0:self.width] = self.src_txt
            frame_preview[0:20, 0:self.width] = self.prev_txt
            frame_preview[0:self.height, 0:1] = 0

            cv2.putText(frame_source, "#" + str(config.importer.frame),
                        (to_int(self.width / 2), 12), font, .7,
                        (255, 255, 255), 0, cv2.LINE_4)
            i = 0
            while i < 5:
                frame_source[to_int(self.height * i / 5) -
                             1:to_int(self.height * i / 5) + 1,
                             0:self.width] = (100, 100, 100)
                i += 1

            cv2.imshow("CONFIGURATION", np.hstack(
                (frame_source, frame_preview)))
            cv2.imshow("BINARY", np.vstack((stock_P, stock_CR)))

            self.out.write(frame_preview)

            self.key = cv2.waitKey(50)

            if self.key == ord("-"):
                cv2.imwrite(
                    "screen_cap_fr{}.jpg".format(config.importer.frame),
                    frame_preview)

            self.key_listener(self.key)

        else:
            # real tracking
            self.out.write(frame_preview)

            cv2.imshow("TRACKING", frame_preview)

            key = cv2.waitKey(1)

            if key == ord("q"):
                config.engine.release()