Beispiel #1
0
 def place_cross(self, source: np.ndarray, point: tuple,
                 color: tuple) -> None:
     try:
         source[to_int(point[1] - 3):to_int(point[1] + 4),
                to_int(point[0])] = color
         source[to_int(point[1]),
                to_int(point[0] - 3):to_int(point[0] + 4)] = color
     except:
         pass
Beispiel #2
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

            while n < self.norm_cr_artefact:
                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
Beispiel #3
0
    def track(self, last: bool = False):

        try:

            # FIXME: while the hasattr is fixing the exception, it is not the
            #        most elegant solution (nor probably the right one)
            if config.engine.blink_i == 1 and hasattr(self,
                                                      'standard_corners'):
                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 has not been initialized yet
            if self.center == -1:
                return False

            # center has not been initialized yet
            if self.center == -1:
                return False

            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:
            import traceback
            traceback.print_exc()
            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
Beispiel #4
0
    def walkout(self, total_n=0):
        """
        Points are iteratively translated centrifugally to a limit,
        and in an equally distributed manner (θ=360/n) from a center.
        Notably, n is offset based on the width and height of the previously detected ellipsoid.

        Similar to what was described by Sakatani and Isa (2004).
        """

        x = point_source.copy()
        y = point_source.copy()
        step_list = step_list_source.copy()

        offset = self.processor.walkout_offset
        b = 0
        for i, cos_sin in enumerate(cos_sin_steps):

            cos, sin = cos_sin

            x[i] = self.center[0] + cos * offset
            y[i] = self.center[1] + sin * offset

            insidemark = False

            for _ in limit:
                b += 1
                # If walkout coordinate hits out-of-contour area, break out of the loop.
                try:
                    pixel = self.processor.area[to_int(y[i]), to_int(x[i])]

                    if pixel != 255:
                        if pixel == 100:  # inside mark
                            if insidemark == False:
                                lastcoord = x[i], y[i]
                                insidemark = True

                        else:
                            if insidemark:
                                x[i], y[i] = lastcoord

                            break
                    else:
                        insidemark = False

                except:
                    # Walkout hit outside of Processor area. Go back to previous in-bounds point, then break.
                    x[i] -= cos
                    y[i] -= sin
                    step_list[i] -= 1
                    break

                x[i] += cos
                y[i] += sin
                step_list[i] += 1

        coord_length = len(x)

        if b <= len(x) + 2:
            return False

        if coord_length < 5:
            return False

        x, y, coord_length = self.filter(x, y, coord_length, step_list)

        if coord_length < 4:
            return False

        self.rx, self.ry = x[(0 != x)], y[(0 != y)]

        return True
Beispiel #5
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()