예제 #1
0
def get_person_image(personId):
    "生成并返回人物图像的filepath"
    conn = db.get_connection()
    try:
        sql = ("select face.id, photo.path, face.rotation, face.location"
               " from tbl_face face"
               " inner join tbl_photo photo on face.photo_id = photo.id"
               " where face.person_id = %s"
               " order by photo.taken_time desc"
               " limit 1")
        with conn.cursor() as cursor:
            cursor.execute(sql, (personId, ))
            row = cursor.fetchone()
            if row is None:
                return None
            faceId = row[0]
            photoPath = row[1]
            rotation = row[2]
            faceBox = row[3]
            # 截取人脸
            image = cv2.imread(photoPath)
            logger = get_logger()
            logger.info(f"photoPath is {photoPath}")
            logger.info(f"rotation is {rotation} type {type(rotation)}")
            image = rotate_image(image, rotation)
            (top, right, bottom, left) = faceBox
            faceImage = image[top:bottom, left:right]
            # 保存到磁盘
            os.makedirs(settings.PERSON_IMAGES_HOME, exist_ok=True)
            path = os.path.join(settings.PERSON_IMAGES_HOME, f"{faceId}.jpg")
            cv2.imwrite(path, faceImage)
            return path
    finally:
        db.put_connection(conn)
예제 #2
0
def count_photos():
  conn = db.get_connection()
  try:
      with conn.cursor() as cursor:
        cursor.execute("SELECT count(id) from tbl_photo")
        row = cursor.fetchone()
        return row[0]
  finally:
    db.put_connection(conn)
예제 #3
0
def rename_person(personId, name):
    conn = db.get_connection()
    try:
        with conn.cursor() as cursor:
            cursor.execute("update tbl_person set name=%s where id=%s",
                           (name, personId))
        conn.commit()
    finally:
        db.put_connection(conn)
예제 #4
0
def list_photos(limit = 20, offset = 0):
  conn = db.get_connection()
  try:
    sql = f"SELECT id, digest from tbl_photo order by taken_time desc LIMIT {limit} OFFSET {offset}"
    with conn.cursor() as cursor:
      cursor.execute(sql)
      rows = cursor.fetchall() 
      return [{"id": row[0], "digest": row[1]} for row in rows]
  finally:
    db.put_connection(conn)
예제 #5
0
def link_photos_to_person(photoIds, personId, newPersonId):
    "关联人物和照片, newPersonId可以为null"
    conn = db.get_connection()
    try:
        with conn.cursor() as cursor:
            ensure_hidden_person(cursor)
            cursor.execute(
                "update tbl_face set person_id=%s where person_id=%s and photo_id in %s",
                (newPersonId, personId, tuple(photoIds)))
        conn.commit()
    finally:
        db.put_connection(conn)
예제 #6
0
def create_person(name):
    "创建Person,返回person ID"
    conn = db.get_connection()
    try:
        with conn.cursor() as cursor:
            cursor.execute(
                "insert into tbl_person (name) values (%s) returning id",
                (name, ))
            row = cursor.fetchone()
            conn.commit()
            return row[0]
    finally:
        db.put_connection(conn)
예제 #7
0
def count_person_photos(personId):
    "返回包含某个人物的照片总数"
    conn = db.get_connection()
    try:
        sql = ("select count(DISTINCT photo.id)"
               " from tbl_photo photo"
               " inner join tbl_face face on photo.id = face.photo_id"
               " where face.person_id = %s")
        with conn.cursor() as cursor:
            cursor.execute(sql, (personId, ))
            row = cursor.fetchone()
            return row[0]
    finally:
        db.put_connection(conn)
예제 #8
0
def remove_persons(ids):
    conn = db.get_connection()
    try:
        with conn.cursor() as cursor:
            ensure_hidden_person(cursor)
            idsToRemove = tuple(ids)
            cursor.execute(
                "update tbl_face set person_id=-1 where person_id in %s",
                (idsToRemove, ))
            cursor.execute("delete from tbl_person where id in %s",
                           (idsToRemove, ))
        conn.commit()
    finally:
        db.put_connection(conn)
예제 #9
0
def merge_persons(ids):
    conn = db.get_connection()
    try:
        with conn.cursor() as cursor:
            newId = ids[0]
            idsToRemove = tuple(ids[1:])
            cursor.execute(
                "update tbl_face set person_id=%s where person_id in %s",
                (newId, idsToRemove))
            cursor.execute("delete from tbl_person where id in %s",
                           (idsToRemove, ))
        conn.commit()
    finally:
        db.put_connection(conn)
def test_grouping_result():
    conn = db.get_connection()
    try:
        sql = ("select id, name from tbl_person where id != -1")
        with conn.cursor() as cursor:
            cursor.execute(sql)
            rows = cursor.fetchall()
            persons = [{"id": row[0], "name": row[1]} for row in rows]

            for person in persons:
                test_photos_in_person(cursor, person['id'])
                conn.commit()
    finally:
        db.put_connection(conn)
예제 #11
0
def reload_faces():
    logger = get_logger()
    logger.info("=========== start reload_faces() ===========")
    conn = db.get_connection()
    try:
        with conn.cursor() as cursor:
            cursor.execute(
                "select id, path from tbl_photo where face_detect_done=false")
            rows = cursor.fetchall()
            logger.info("start to detect&encode faces")
            global time_detect_faces, time_encode_faces
            time_detect_faces = 0
            time_encode_faces = 0
            for (i, row) in enumerate(rows):
                photoId = row[0]
                photoPath = row[1]
                # 人脸检测、编码
                encode_faces(photoId, photoPath, cursor)
                conn.commit()
                logger.info(f"encoding face {i}/{len(rows)}")
            logger.info(f"time_detect_faces: {time_detect_faces} seconds")
            logger.info(f"time_encode_faces: {time_encode_faces} seconds")
            logger.info("end detect&encode faces")

            # 自动估算最佳eps值
            logger.info("start to calculate BestEps")
            start = time.time()
            global bestGuessEps
            bestGuessEps = select_cluster_param(cursor)
            end = time.time()
            logger.info(f"calculate BestEps takes {end-start} seconds")
            logger.info(f"DBSCAN param eps value: {bestGuessEps}")

            # 人脸分类
            start = time.time()
            classify_faces(cursor)
            end = time.time()
            logger.info(f"classify_faces takes {end-start} seconds")
            conn.commit()

            # 人脸聚类
            start = time.time()
            cluster_faces(cursor)
            end = time.time()
            logger.info(f"cluster_faces takes {end-start} seconds")
            conn.commit()
    finally:
        db.put_connection(conn)
        logger.info("end reload_faces()")
예제 #12
0
def list_person_photos(personId, limit=20, offset=0):
    "返回包含某个人物的照片列表"
    conn = db.get_connection()
    try:
        sql = ("select photo.id, photo.digest"
               " from tbl_photo photo"
               " inner join tbl_face face on photo.id = face.photo_id"
               " where face.person_id = %s"
               " group by photo.id"
               " order by photo.taken_time desc"
               " LIMIT %s OFFSET %s")
        with conn.cursor() as cursor:
            cursor.execute(sql, (personId, limit, offset))
            rows = cursor.fetchall()
            return [{"id": row[0], "digest": row[1]} for row in rows]
    finally:
        db.put_connection(conn)
예제 #13
0
def list_persons():
    conn = db.get_connection()
    try:
        sql = (
            "select person.id, person.name, count(DISTINCT photo.id) photoCount"
            " from tbl_person person"
            " inner join tbl_face face on person.id = face.person_id"
            " inner join tbl_photo photo on face.photo_id = photo.id"
            " where person.id != -1"
            " group by person.id"
            " order by photoCount desc")
        with conn.cursor() as cursor:
            cursor.execute(sql)
            rows = cursor.fetchall()
            return [{
                "id": row[0],
                "name": row[1],
                "photoCount": row[2]
            } for row in rows]
    finally:
        db.put_connection(conn)
예제 #14
0
def reload_photo(imagePath):
  logger = get_logger()
  conn = db.get_connection()
  try:
    with conn.cursor() as cursor:
      logger.info(f"reload image {imagePath}")
      if os.path.exists(imagePath):
        do_reload_photo(cursor, imagePath)
      else:
        # 文件被删除
        cursor.execute("select id, digest from tbl_photo where path=%s", (imagePath,))
        row = cursor.fetchone()
        if row:
          id = row[0]
          cursor.execute("delete from tbl_face where photo_id=%s", (id,))
          cursor.execute("delete from tbl_photo where id=%s", (id,))
      conn.commit()
  except Exception as e:
    logger.error(e)
  finally:
    db.put_connection(conn)
예제 #15
0
def get_photo_path(id):
  """获取照片preview的文件路径"""
  conn = db.get_connection()
  try:
    sql = "SELECT path,digest from tbl_photo where id=%(id)s"
    with conn.cursor() as cursor:
      cursor.execute(sql, {"id": id})
      row = cursor.fetchone()
      if row is None:
        return None
      else:
        path = row[0]
        digest = row[1]
        img = cv2.imread(path)
        previewImg = preview_image(img, 800)
        previewPath = os.path.join(settings.SMALL_PHOTO_HOME, f"{digest}.jpg")
        os.makedirs(settings.SMALL_PHOTO_HOME, exist_ok=True)
        cv2.imwrite(previewPath, previewImg)
        return previewPath
  finally:
    db.put_connection(conn)
예제 #16
0
def do_reload_photos():
  reloadStartTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
  imagePaths = paths.list_images(settings.USER_PHOTO_HOME)
  conn = db.get_connection()
  try:
    with conn.cursor() as cursor:
      for imagePath in imagePaths:
        try:
          do_reload_photo(cursor, imagePath)
          conn.commit()
        except Exception as e:
          logger = get_logger()
          logger.error(e)
      # 删除文件不存在的photo记录及关联的face
      cursor.execute("select id from tbl_photo where last_scanned < TIMESTAMP %s", (reloadStartTime,))
      rows = cursor.fetchall()
      for row in rows:
        id = row[0]
        cursor.execute("delete from tbl_face where photo_id=%s", (id,))
        cursor.execute("delete from tbl_photo where id=%s", (id,))
      conn.commit()
  finally:
    db.put_connection(conn)