Ejemplo n.º 1
0
class CDSST:
    def __init__(self):
        path = 'frames/'
        day_images = SkyCameraFile.glob(path)
        day_images.sort()
        times = np.array(
            [SkyCameraFile.parseTime(x).datetime for x in day_images])

        self.day_images = day_images
        self.times = times

        self.calibration = Calibration(catalog=SkyCatalog(True))
        self.calibration.load()

        self.helper = CloudDetectionHelper()

        try:
            with open('cd_sst.cache', 'rb') as f:
                self.cache = pickle.load(f)
        except:
            self.cache = pd.DataFrame(index=pd.Index([], dtype=np.datetime64),
                                      columns=[
                                          'pos_x', 'pos_y', 'radius',
                                          'stripe_min', 'stripe_max'
                                      ])

    def save_cache(self):
        with open('cd_sst.cache', 'wb') as f:
            pickle.dump(self.cache, f)

    def detect(self, filename):
        image = cv2.imread(filename)
        time = SkyCameraFile.parseTime(filename).datetime

        mask = np.uint8(self.helper.get_mask(image).copy())

        self.calibration.selectImage(filename)
        pos = self.calibration.project()
        pos = (pos[0], pos[1])

        if time in self.cache.index:
            sun_x, sun_y, radius, min_x, max_x = self.cache.loc[time]

            sun = None
            sun_pos = None

            if not np.isnan(sun_x):
                sun_pos = (sun_x, sun_y)
                sun = CDSunRemoval.circle_mask(sun_pos, radius, mask.shape)

            sun_line = None
            if not np.isnan(min_x):
                sun_line = np.zeros(mask.shape, np.uint8)
                sun_line[:, min_x:max_x + 1] = True

        else:
            sun_line, min_x, max_x = CDSunRemoval.find_sun_line(image, pos)

            sun, sun_pos, radius = CDSunRemoval.find_sun(pos, mask)

            sun_x = sun_y = None
            if sun_pos is not None:
                sun_x = sun_pos[0]
                sun_y = sun_pos[1]

            self.cache.loc[time] = [sun_x, sun_y, radius, min_x, max_x]

        if sun_pos is None:
            sun_pos = pos

        mask = self.helper.fullmask.copy()
        mask[self.helper.mask == 0] = 0
        mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE,
                                np.ones((11, 11), np.uint8))

        _, contours, _ = cv2.findContours(mask, cv2.RETR_LIST,
                                          cv2.CHAIN_APPROX_SIMPLE)

        cloudiness = np.ones(mask.shape, np.float32) * .5

        did_sun = False

        for contour in contours:
            area = cv2.contourArea(contour)
            is_sun = False

            if area > 100:  # TODO: try different numbers
                single_contour = np.zeros(mask.shape, np.uint8)
                cv2.drawContours(single_contour, [contour], 0, 1, cv2.FILLED)

                if sun is not None and not did_sun:
                    sun_area = np.sum(sun[self.helper.mask == 1])

                    if area > 0.9 * sun_area:
                        joint_area = np.sum(np.logical_and(
                            single_contour, sun))

                        if sun_area / joint_area > 0.9:
                            is_sun = True

                    if is_sun:
                        if sun_area * 1.2 < area:
                            difference = np.uint8(
                                np.logical_and(np.logical_not(sun),
                                               single_contour))
                            _, contours2, _ = cv2.findContours(
                                difference, cv2.RETR_LIST,
                                cv2.CHAIN_APPROX_SIMPLE)
                            # filter smaller ones here! currently done with the if at the beginning
                            contours += contours2
                            did_sun = True

                if not is_sun:
                    cloudiness[single_contour > 0] = 1.0

        b, g, r = cv2.split(np.int32(image))

        mask = self.helper.mask

        rmb = r - b
        rmb[mask == 0] = 0

        cloudiness[rmb < -10] = 0
        cloudiness[rmb > 50] = 1

        delta = np.timedelta64(39, 's')
        delta2 = np.timedelta64(0, 's')
        time_diff = time - self.times
        before = np.logical_and(time_diff > delta2, time_diff < delta)

        if np.sum(before) == 0:
            raise ValueError('No previous image found.')

        current_index = np.where(before)[0][0]

        prev_img = cv2.imread(self.day_images[current_index])

        gray_prev = cv2.cvtColor(prev_img, cv2.COLOR_BGR2GRAY)
        gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

        flow = cv2.calcOpticalFlowFarneback(gray_prev, gray_image, None, 0.5,
                                            3, 15, 3, 5, 1.2, 0)
        flow2 = -cv2.calcOpticalFlowFarneback(gray_image, gray_prev, None, 0.5,
                                              3, 15, 3, 5, 1.2, 0)

        mag1, _ = cv2.cartToPolar(flow[..., 0], flow[..., 1])
        mag2, _ = cv2.cartToPolar(flow2[..., 0], flow2[..., 1])

        movement = np.logical_and(mag1 > 1, mag2 > 1)
        no_movement = np.logical_not(movement)

        brightness = np.mean(image, 2)

        cloudiness[np.logical_and(movement == 1, cloudiness != 0)] = 1
        cloudiness[self.helper.mask == 0] = 1
        if sun is not None:
            cloudiness[sun == 1] = 1

        if sun_line is not None:
            sun_line_dilated = cv2.morphologyEx(sun_line, cv2.MORPH_DILATE,
                                                np.ones((1, 3)))
            cloudiness[sun_line_dilated == 1] = 1

        y, x = np.mgrid[0:brightness.shape[0], 0:brightness.shape[1]]

        x1 = []
        y1 = []
        out = []

        for i in range(brightness.shape[0]):
            for j in range(brightness.shape[1]):
                if cloudiness[i, j] != 1:
                    x1.append(x[i, j])
                    y1.append(y[i, j])
                    out.append(brightness[i, j])

        x = np.array(x1) - sun_pos[0]
        y = np.array(y1) - sun_pos[1]

        out = np.array(out)

        dist = np.sqrt(x * x + y * y)

        A = np.array([dist, np.ones(x.shape), x, y]).transpose()
        A_inv = np.linalg.pinv(A)

        param = np.dot(A_inv, out)

        y, x = np.mgrid[0:brightness.shape[0], 0:brightness.shape[1]]
        x = x - pos[0]
        y = y - pos[1]
        dist = np.sqrt(x * x + y * y)
        A = np.array([dist, np.ones(x.shape), x, y]).transpose()
        gradient = np.dot(A, param).transpose()

        rect_size = 15

        rect_border = (rect_size - 1) // 2

        brightness_norm = brightness - gradient

        stddev = np.zeros(brightness.shape)

        for y in range(image.shape[0]):
            for x in range(image.shape[1]):
                if cloudiness[y, x] == 1:
                    continue

                lx = x - rect_border
                rx = x + rect_border + 1
                uy = y - rect_border
                dy = y + rect_border + 1

                if lx < 0: lx = 0
                if uy < 0: uy = 0
                if rx > image.shape[1]: rx = image.shape[1]
                if dy > image.shape[0]: dy = image.shape[0]

                mask_part = cloudiness[uy:dy, lx:rx]
                stddev[y, x] = np.std(brightness_norm[uy:dy,
                                                      lx:rx][mask_part != 1])

        def_clear = np.sum(cloudiness == 0)

        cloudiness[cloudiness == 0.5] = (stddev > 3)[cloudiness == 0.5]

        if sun is None or (sun_line is None and radius < 100):
            if def_clear < 0.1 * np.sum(self.helper.mask == 1):
                cloudiness[np.logical_and(cloudiness == 0, rmb > -8)] = 1

        cloudiness = self.helper.close_result(cloudiness)

        cloudiness[self.helper.mask == 0] = 0.5

        if sun is not None:
            cloudiness[sun == 1] = 0.5

        if sun_line is not None:
            cloudiness[sun_line_dilated == 1] = 0.5

        return cloudiness

    def get_cloud_cover(self, cloudiness):
        return np.sum(cloudiness == 1) / np.sum(cloudiness != 0.5)
Ejemplo n.º 2
0
class StarCheckerHelper:
	def __init__(self, calibration_file):
		self.calibration = Calibration()
		self.calibration.load(calibration_file)
	
	def prepare(self, path, star_finder):
		with warnings.catch_warnings():
			warnings.simplefilter('ignore', AstropyWarning)
			self.calibration.selectImage(path)
		
		self.names, self.vmag, alt, az = self.calibration.catalog.filter(Configuration.min_alt * u.deg, Configuration.max_mag)
		
		altaz = np.array([alt.radian, az.radian]).transpose()
		
		self.pos = np.column_stack(self.calibration.project(altaz))
		
		self.finder = star_finder
		
		self.image = cv2.imread(path)
		
		self.finder.setImage(self.image)
		
		self.altaz = np.array([alt.degree, az.degree]).transpose()
	
	def count_stars(self):
		min_az = 0
		max_az = 360
		min_alt = Configuration.min_alt
		max_alt = 90
		alt_step = Configuration.alt_step
		az_step = Configuration.az_step
		
		alt_bins = int((max_alt - min_alt) / alt_step)
		az_bins = int((max_az - min_az) / az_step)
		
		counts = np.zeros([alt_bins, az_bins, 4])
		
		for alt_bin in range(alt_bins):
			alt = min_alt + alt_step * alt_bin
			for az_bin in range(az_bins):
				az = min_az + az_step * az_bin
				
				counts[alt_bin, az_bin, 2] = alt
				counts[alt_bin, az_bin, 3] = az
				
				for i in range(self.pos.shape[0]):
					aa = self.altaz[i]
					if aa[0] > alt and aa[0] <= alt + alt_step and aa[1] > az and aa[1] <= az + az_step:
						counts[alt_bin, az_bin, 0] += 1
						if self.finder.isStar(self.pos[i][0], self.pos[i][1]):
							counts[alt_bin, az_bin, 1] += 1
		
		return counts
	
	def get_image(self):
		result = self.image.copy()
		
		good_color = (0, 255, 0)
		bad_color = (0, 0, 255)
		
		for i in range(self.pos.shape[0]):
			if self.finder.isStar(self.pos[i][0], self.pos[i][1]):
				color = good_color
			else:
				color = bad_color
			cv2.circle(result, (int(self.pos[i][0]), int(self.pos[i][1])), 3, color)
		
		return result
Ejemplo n.º 3
0
class CDSST:
    def __init__(self):
        path = 'frames/'
        day_images = SkyCameraFile.glob(path)
        day_images.sort()
        times = np.array([SkyCameraFile.parseTime(x).datetime for x in day_images])
        
        self.day_images = day_images
        self.times = times
        
        self.calibration = Calibration(catalog=SkyCatalog(True))
        self.calibration.load()

        self.helper = CloudDetectionHelper()
        
        try:
            with open('cd_sst.cache', 'rb') as f:
                self.cache = pickle.load(f)
        except:
            self.cache = pd.DataFrame(index=pd.Index([], dtype=np.datetime64), columns=['pos_x', 'pos_y', 'radius', 'stripe_min', 'stripe_max'])
        
    def save_cache(self):
        with open('cd_sst.cache', 'wb') as f:
            pickle.dump(self.cache, f)
        
    def detect(self, filename):
        image = cv2.imread(filename)
        time = SkyCameraFile.parseTime(filename).datetime
        
        mask = np.uint8(self.helper.get_mask(image).copy())

        self.calibration.selectImage(filename)
        pos = self.calibration.project()
        pos = (pos[0], pos[1])

        if time in self.cache.index:
            sun_x, sun_y, radius, min_x, max_x = self.cache.loc[time]
            
            sun = None
            sun_pos = None
            
            if not np.isnan(sun_x):
                sun_pos = (sun_x, sun_y)
                sun = CDSunRemoval.circle_mask(sun_pos, radius, mask.shape)
                
            sun_line = None
            if not np.isnan(min_x):
                sun_line = np.zeros(mask.shape, np.uint8)
                sun_line[:, min_x:max_x + 1] = True
            
        else:
            sun_line, min_x, max_x = CDSunRemoval.find_sun_line(image, pos)

            sun, sun_pos, radius = CDSunRemoval.find_sun(pos, mask)
            
            sun_x = sun_y = None
            if sun_pos is not None:
                sun_x = sun_pos[0]
                sun_y = sun_pos[1]
            
            self.cache.loc[time] = [sun_x, sun_y, radius, min_x, max_x]

        if sun_pos is None:
            sun_pos = pos

        mask = self.helper.fullmask.copy()
        mask[self.helper.mask == 0] = 0
        mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((11, 11), np.uint8))

        _, contours, _ = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

        cloudiness = np.ones(mask.shape, np.float32) * .5

        did_sun = False

        for contour in contours:
            area = cv2.contourArea(contour)
            is_sun = False

            if area > 100: # TODO: try different numbers
                single_contour = np.zeros(mask.shape, np.uint8)
                cv2.drawContours(single_contour, [contour], 0, 1, cv2.FILLED)

                if sun is not None and not did_sun:
                    sun_area = np.sum(sun[self.helper.mask == 1])

                    if area > 0.9 * sun_area:
                        joint_area = np.sum(np.logical_and(single_contour, sun))

                        if sun_area / joint_area > 0.9:
                            is_sun = True

                    if is_sun:
                        if sun_area * 1.2 < area:
                            difference = np.uint8(np.logical_and(np.logical_not(sun), single_contour))
                            _, contours2, _ = cv2.findContours(difference, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
                            # filter smaller ones here! currently done with the if at the beginning
                            contours += contours2
                            did_sun = True

                if not is_sun:
                    cloudiness[single_contour > 0] = 1.0



        b, g, r = cv2.split(np.int32(image))

        mask = self.helper.mask

        rmb = r - b
        rmb[mask == 0] = 0

        cloudiness[rmb < -10] = 0
        cloudiness[rmb > 50] = 1

        delta = np.timedelta64(39, 's')
        delta2 = np.timedelta64(0, 's')
        time_diff = time - self.times
        before = np.logical_and(time_diff > delta2, time_diff < delta)

        if np.sum(before) == 0:
            raise ValueError('No previous image found.')

        current_index = np.where(before)[0][0]

        prev_img = cv2.imread(self.day_images[current_index])

        gray_prev = cv2.cvtColor(prev_img, cv2.COLOR_BGR2GRAY)
        gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

        flow = cv2.calcOpticalFlowFarneback(gray_prev, gray_image, None, 0.5, 3, 15, 3, 5, 1.2, 0)
        flow2 = -cv2.calcOpticalFlowFarneback(gray_image, gray_prev, None, 0.5, 3, 15, 3, 5, 1.2, 0)

        mag1, _ = cv2.cartToPolar(flow[...,0], flow[...,1])
        mag2, _ = cv2.cartToPolar(flow2[...,0], flow2[...,1])

        movement = np.logical_and(mag1 > 1, mag2 > 1)
        no_movement = np.logical_not(movement)

        brightness = np.mean(image, 2)

        cloudiness[np.logical_and(movement == 1, cloudiness != 0)] = 1
        cloudiness[self.helper.mask == 0] = 1
        if sun is not None:
            cloudiness[sun == 1] = 1

        if sun_line is not None:
            sun_line_dilated = cv2.morphologyEx(sun_line, cv2.MORPH_DILATE, np.ones((1, 3)))
            cloudiness[sun_line_dilated == 1] = 1

        y, x = np.mgrid[0:brightness.shape[0], 0:brightness.shape[1]]

        x1 = []
        y1 = []
        out = []

        for i in range(brightness.shape[0]):
            for j in range(brightness.shape[1]):
                if cloudiness[i, j] != 1:
                    x1.append(x[i, j])
                    y1.append(y[i, j])
                    out.append(brightness[i, j])

        x = np.array(x1) - sun_pos[0]
        y = np.array(y1) - sun_pos[1]

        out = np.array(out)

        dist = np.sqrt(x * x + y * y)

        A = np.array([dist, np.ones(x.shape), x, y]).transpose()
        A_inv = np.linalg.pinv(A)

        param = np.dot(A_inv, out)

        y, x = np.mgrid[0:brightness.shape[0], 0:brightness.shape[1]]
        x = x - pos[0]
        y = y - pos[1]
        dist = np.sqrt(x * x + y * y)
        A = np.array([dist, np.ones(x.shape), x, y]).transpose()
        gradient = np.dot(A, param).transpose()

        rect_size = 15

        rect_border = (rect_size - 1) // 2

        brightness_norm = brightness - gradient

        stddev = np.zeros(brightness.shape)

        for y in range(image.shape[0]):
            for x in range(image.shape[1]):
                if cloudiness[y, x] == 1:
                    continue

                lx = x - rect_border
                rx = x + rect_border + 1
                uy = y - rect_border
                dy = y + rect_border + 1

                if lx < 0: lx = 0
                if uy < 0: uy = 0
                if rx > image.shape[1]: rx = image.shape[1]
                if dy > image.shape[0]: dy = image.shape[0]
                    
                mask_part = cloudiness[uy:dy, lx:rx]
                stddev[y, x] = np.std(brightness_norm[uy:dy, lx:rx][mask_part != 1])

        def_clear = np.sum(cloudiness == 0)

        cloudiness[cloudiness == 0.5] = (stddev > 3)[cloudiness == 0.5]

        if sun is None or (sun_line is None and radius < 100):
            if def_clear < 0.1 * np.sum(self.helper.mask == 1):
                cloudiness[np.logical_and(cloudiness == 0, rmb > -8)] = 1
        
        cloudiness = self.helper.close_result(cloudiness)

        cloudiness[self.helper.mask == 0] = 0.5

        if sun is not None:
            cloudiness[sun == 1] = 0.5

        if sun_line is not None:
            cloudiness[sun_line_dilated == 1] = 0.5

        return cloudiness

    def get_cloud_cover(self, cloudiness):
        return np.sum(cloudiness == 1) / np.sum(cloudiness != 0.5)