示例#1
0
def calibrateCamera():
    '''Calibrate the camera. Get the true FPS (including processing) from the camera'''
    print('{} [CLIENT]: Calibrating camera'.format(timestamp()))
    camera = cv.VideoCapture(0)
    width = camera.get(cv.CAP_PROP_FRAME_WIDTH)
    height = camera.get(cv.CAP_PROP_FRAME_HEIGHT)

    # Adjust frame size if it is excessively large
    while width * height  >= 1000000:
        width *= 0.75
        height *= 0.75

    # OpenCV will override input and round to the closest (recognized) resolution. For example, I set res to 1900x1070 and it will override as 1920x1080.
    camera.set(3, width)
    camera.set(4, height)

    if not camera.isOpened():
        # Attempt to open capture device once more, after a failure
        camera.open()
        if not camera.isOpened():
            print('{} [CLIENT]: Issue opening camera'.format(timestamp()))
            exit()

    start_time = time.time()
    count = 0
    while int(time.time() - start_time) < 10:
        ret, frame = camera.read()
        count += 1 # number of frames

    return camera, int(count / 10)
示例#2
0
def alert(id):
    '''Notify (via email) that motion has been detected.'''
    gmail_user = ENV('GMAIL_USER')
    gmail_password = ENV('GMAIL_APP_PASSWORD')

    sent_from = gmail_user
    to = []  # Email recipients here
    subject = 'ALERT - Security System'
    body = 'ALERT: Movement has been detected by the security system on {} by camera {}'.format(
        datetime.datetime.now().strftime("%d/%m/%Y at %H:%M:%S"), id)

    email_text = """\
    From: %s
    To: %s
    Subject: %s

    %s
    """ % (sent_from, ", ".join(to), subject, body)

    if len(to) == 0:
        return
    try:
        server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
        server.ehlo()
        server.login(gmail_user, gmail_password)
        server.sendmail(sent_from, to, email_text)
        server.close()

        print(
            '{} [SERVER]: Movement detected. Alerts successfully sent.'.format(
                helper.timestamp()))
    except:
        print('{} [SERVER]: There was an issue sending alerts.'.format(
            helper.timestamp()))
示例#3
0
def main():
    '''Client that connects and streams video to server.'''

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.connect((HOST, PORT))

    confirmRelationship(server)
    print('{} [CLIENT]: Established connection with server'.format(timestamp()))

    # Set and calibrate camera
    camera, FPS = calibrateCamera()

    print('{} [CLIENT]: Beginning stream to server'.format(timestamp()))
    ret, frame1 = camera.read()
    ret, frame2 = camera.read()
    connection_failed = False

    while camera.isOpened():
        detected_motion, motion_frame = detectMotion(frame1, frame2)
        frame = drawTime(motion_frame, int(camera.get(3)), int(camera.get(4)))
        data = {'FRAME': frame,
                'MOTION': detected_motion,
                'FPS': FPS,
                'WIDTH': int(camera.get(3)),
                'HEIGHT': int(camera.get(4))
                }
        pickled_data = pickle.dumps(data)

        try:
            server.sendall(struct.pack("P", len(pickled_data))+pickled_data)

        except socket.error:
            # Handle connection issues
            print('{} [CLIENT]: Connection to server disrupted'.format(timestamp()))
            connected = False
            server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

            while not connected:
                # Try to reconnect
                try:
                    server.connect((HOST, PORT))
                    confirmRelationship(server)
                    connected = True
                    if connection_failed:
                        # Connection was re-established after it recently failed
                        print('{} [CLIENT]: Re-established connection with server'.format(timestamp()))
                        connection_failed = False
                except socket.error:
                    connected = False
                    connection_failed = True
                    camera.release()
                    time.sleep(2.5) # Wait before trying to reconnect
                    print('{} [CLIENT]: Attempting to re-establish connection with server'.format(timestamp()))
                    camera.open(0)

        frame1 = frame2
        ret, frame2 = camera.read()
        cv.waitKey(1)
示例#4
0
def processFrame(data, address, id, recording, FRAMES):
    '''Process the frame. Handle recording and alert decisions.'''
    # Handle recording behavior
    # If there is motion in this frame or there was recently motion (and it is recording), then act accordingly
    # Ignore if this is the first frame sent from client
    if (data['MOTION'] and len(FRAMES[address[1]]) != 1) or recording:
        if (helper.getStatus() == 'on') and not recording:
            alert(
                id
            )  # Alert when motion (recording) first starts and alerts are enabled

        recording, output_file = record(FRAMES[address[1]], recording,
                                        int(ENV('SECONDS')), id)
        processed_frame = helper.drawRecording(data['FRAME'], data['WIDTH'],
                                               data['HEIGHT'])

        if not recording:
            # No longer recording. Throw away all but last few FRAMES
            temp_frames = FRAMES[address[1]]
            temp_frames = temp_frames[(len(temp_frames) -
                                       (data['FPS'] * int(ENV('SECONDS')))):]
            if output_file is not None:
                print('{} [SERVER]: Video recording saved to {}'.format(
                    helper.timestamp(), output_file))
        else:
            temp_frames = None
    else:
        processed_frame = data['FRAME']
        temp_frames = None

    return processed_frame, recording, temp_frames
示例#5
0
def record(frames, already_recording, SECONDS, id):
    '''Record video when motion is detected. Includes the few seconds prior to motion detection and few seconds after the motion stops.'''
    FPS = frames[0]['FPS']
    WIDTH = frames[0]['WIDTH']
    HEIGHT = frames[0]['HEIGHT']
    motion = []

    for frame in frames:
        motion.append(frame['MOTION'])

    # Check if there has been motion in the last few seconds
    start = len(motion) - (FPS * SECONDS)
    # If the start index is less than 0, then default to True.
    movement_lately = True if (start < 0 or
                               (True in motion[start:])) else False
    output_file = None

    if not movement_lately:
        #stop the recording. Write to a video file
        print('{} [SERVER]: Saving recording from Client {} '.format(
            helper.timestamp(), id))

        # Ensure that user has a correct video type
        if ENV('RECORDING_TYPE') == 'mp4':
            fourcc = cv.VideoWriter_fourcc(*'mp4v')
        elif ENV('RECORDING_TYPE') == 'avi':
            fourcc = cv.VideoWriter_fourcc(*'XVID')
        else:
            print(
                '{} [SERVER]: Can not record video of type: {}\nChange the RECORDING_TYPE to one of the acceptable video types (listed under step 2a on README) in your .env and restart the server to enable video recordings to be saved'
                .format(helper.timestamp(), ENV('RECORDING_TYPE')))
            return False, None

        output_file = "static/recordings/{}CAM{}.{}".format(
            datetime.datetime.now().strftime("%m-%d-%Y/%H_%M_%S"), id,
            ENV('RECORDING_TYPE'))
        os.makedirs(os.path.dirname(output_file), exist_ok=True)
        open(output_file, 'a+').close()
        output = cv.VideoWriter(output_file, fourcc, FPS, (WIDTH, HEIGHT),
                                True)

        for frame in frames:
            output.write(helper.drawRecording(frame['FRAME'], WIDTH, HEIGHT))

        output.release()  # Completed writing to output file

    return movement_lately, output_file
示例#6
0
def disconnect(client, address, FRAMES, id):
    '''Handle client disconnection'''
    print('{} [SERVER]: Socket {} (client {}) disconnected'.format(
        helper.timestamp(), address[1], id))
    helper.setStandby(id)  # Set standby image as frame
    client.close()

    # Remove this process from PROCESSES and update client count
    # TODO: #PROCESSES.pop(id - 1) # camera 3 is index 2 (3rd process) # TODO: see if this works
    FRAMES.pop(address[1], None)
    helper.updateClientCount(helper.getClientCount() - 1)
示例#7
0
def main():
    print('{} [SERVER]: Server running on port {}'.format(
        helper.timestamp(), PORT))

    # Create Server (socket) and bind it to a address/port.
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((HOST, PORT))
    server.listen(MAX_CLIENTS)
    print('{} [SERVER]: Listening for (client) sockets'.format(
        helper.timestamp()))

    while True:
        # Accept client connection
        client, address = server.accept()
        client.settimeout(5.0)

        if helper.isBlacklisted(
                address[0]) or helper.getClientCount() == MAX_CLIENTS:
            # Close connection since they are blacklisted or
            # there are already the max number of clients connected.
            print('{} [SERVER]: Blacklisted IP {} attempted to connect'.format(
                helper.timestamp(), address[0]))
            client.close()
            continue  # Wait for next client

        # Only continue with this client if they send a confirmation message.
        # This is sort of a second handshake before the client establishes a video stream to server.
        try:
            confirmation = client.recv(
                1024).decode()  # Client should be sending confirmation
        except (socket.timeout, UnicodeDecodeError):
            # Client did not send decodable confirmation in time. Add them to the blacklist if they are unrecognized.
            if not helper.isWhitelisted(address[0]):
                helper.addToBlackList(address[0])
                print(
                    '{} [SERVER]: IP {} has been blacklisted for failing to confirm the connection'
                    .format(helper.timestamp(), address[0]))
                client.close()
                continue  # Wait for next client

        # Whitelist client IP, since they connected successfully.
        helper.addToWhiteList(address[0])

        # Begin a process for this client's video stream
        helper.updateClientCount(helper.getClientCount() + 1)
        print('{} [SERVER]: Socket {} connected as client {}'.format(
            helper.timestamp(), address, helper.getClientCount()))

        # Create, save, and start process (camera stream)
        p = process(target=stream_camera,
                    args=(
                        client,
                        address,
                        helper.getClientCount(),
                    ))
        PROCESSES.append(p)
        p.start()

    # Clear PROCESSES
    for p in PROCESSES:
        p.join()  # Join all PROCESSES

    socket.close()  # TODO: see if this should be server.close() instead
示例#8
0
    # Clear PROCESSES
    for p in PROCESSES:
        p.join()  # Join all PROCESSES

    socket.close()  # TODO: see if this should be server.close() instead


if __name__ == '__main__':
    while True:
        try:
            helper.toggleStatus('on')  # Set alert status to 'on' by default
            helper.updateClientCount(
                0
            )  # No clients can be connected on startup. (Connection will be re-established)
            # Set each client default frame and lock to 'unlocked'
            standby = cv.imread('static/standby.jpg', cv.IMREAD_UNCHANGED)
            for i in range(1, 4):
                helper.unlock(i)  # Unlock all frames for next server instance
                #with open('data/stream_frames/{}/frame.jpg'.format(i), 'r') as file:
                cv.imwrite('data/stream_frames/{}/frame.jpg'.format(i),
                           standby)

            main()
        except Exception as e:
            print(e)
            print('{} [SERVER]: Server crashed'.format(helper.timestamp()))

            time.sleep(5)
            print('{} [SERVER]: Restarting server'.format(helper.timestamp()))
示例#9
0
def detectMotion(frame1, frame2):
    '''Detect motion given two frames. Returns boolean and frame with motion area outlined.'''
    # Helpful Source: Divyanshu Shekhar - https://divyanshushekhar.com/motion-detection-opencv/
    difference = cv.absdiff(frame1, frame2)
    gray_difference = cv.cvtColor(difference, cv.COLOR_BGR2GRAY)
    blur = cv.GaussianBlur(gray_difference, (5, 5), 0)
    __, thresh = cv.threshold(blur, 20, 255, cv.THRESH_BINARY)
    dilated = cv.dilate(thresh, None, iterations=3)
    contours, __ = cv.findContours(dilated, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

    detected = False
    frame = frame1.copy()
    for contour in contours:

        (x, y, w, h) = cv.boundingRect(contour)
        # Place date on frame regardless of any movement
        if cv.contourArea(contour) >= THRESHOLD:
            detected = True

            cv.rectangle(frame, (x, y), (x+w, y+h), (255, 255, 255), 1)
            cv.putText(frame, 'MOTION', (10, 20), cv.FONT_HERSHEY_PLAIN, 1.25, (0, 0, 224), 2, cv.FILLED, False)

    return detected, frame

if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        print('{} [CLIENT]: Exiting script because of error:\n{}'.format(timestamp(), e))