Comments 26
А теперь внимание, вопрос на миллион: если всё так тривиально, то почему аналогичную нейросеточку тупо не сделают на сайте, который требует эти фотографии? Ну, чтобы убрать из процесса вот таких вот посредников?
P.S.
Хоть бы самыми ржачными фоточками «до» поделились!
Там же одно из основных требований, что фотография должна быть НЕ обработанная.
Это где так? Оо
Фото ателье когда делают фото на визу её ретушируют, и никаких проблем не возникает
"а консулу маме мы ничего не скажем".
Что на незначительные массовые нарушения закрывают глаза - ещё не оправдание этих нарушений. И да, иногда всё-таки могут забраковать.
Это где так?
Чуть менее, чем везде.
(Но, как всегда — требование есть, а проверки на соответствие ему — нет.)
Ну вот, например, для визы в Японию в требованиях к фотографии прямо указано: "Do NOT use filters". Мне казалось, для визы в США я тоже аналогичное требование видел, но чё-то на их сайте не найду - может, и впрямь, показалось. Разве вот в разделе FAQ есть про красные глаза:
Can I remove the red-eye from my photo?
It is acceptable to use the red-eye reduction option on your digital camera when you are taking the photo. However, you cannot use any photo editing tool to digitally remove the red-eye from your photo. In general, you are not allowed to digitally enhance or alter the photo to change your appearance in any way.
Во всяком случае, обработка типа "resize, rotate and crop" в явном виде позволяется. Что до удаления фона - я не осилил понять, вроде, это "digitally enhance", но не "change your appearance". Ну и отписка "а мы рассмотрим, и, может, отвергнем".
Хоть бы самыми ржачными фоточками «до» поделились!
Спасибо за идею :)
Фоточки до

Примитивный редактор "обрезать/подогнать под нужный размер", вроде, делают, а удаление фона, да чтоб корректно обработало всю волосню по краям - на хера? Так трудно встать на фоне белой стены и щёлкнуть смартфоном физиономию?
А где полные исходники? Мне, например, совершенно не хочется позволять кому попало связывать мой аккаунт в Телеграме с моим фото.
Я может отстал от жизни, но разве в фотоателье не печатают фотки под заданные размеры? Откуда взялись сайты с услугами за 5-12 долларов? Или они высылают бумажные фотки на адрес?
Кейс такой:
Вы заполняете форму на электронную визу и вам надо прикрепить фото - вы дома, а фотоателье далеко.
Сайт предлагает вам сделать фото дома, отправить им - они обрежут задний фон, выравняют как надо и вы получите себе фото которое можно прикрепить.
Нет, бумагу не шлют. Просто готовый файл под нужные требования. По сути, платишь за обрезку и фон
А я пользуюсь вот этой программой. Ну давно не пользовался, но все же. https://www.fourmilab.ch/netpbm/passport_photo/ Эта программа разработана бывшим владельцем AUTOCAD. https://en.wikipedia.org/wiki/John_Walker_(programmer)
У меня есть старенький цветной принтер Canon Selphy CP900. Он очень качественно печатает маленькие фотки 148 x 100 мм. Принтер рекомендую. Качество высше всяких похвал. Печатает на специальной бумаге.
Короче, я фотографирую на карманный фотоаппарат, обрабатываю этой программой, затем печатаю на принтере и разрезаю. Программа работает на Linux по крайней мере. Не знаю как с Windows .
Вообще замечательный дядька. Рекомендую ознакомиться с сайтом. Много интересного.
Недавно делал для себя, чтобы обрезанную в нужных пропорциях цифровую фотографию распечатать в нужном размере на фотопринтере. На скорую руку, багов особо не ловил, но "у меня всё работает". На Linux работает, на Windows не проверял, но тоже должно. Нужны Python 3.x, OpenCV и NumPy (всё ставится моментально из репозиториев или через pip, Python на Linux обычно и так есть уже).
Код
#!/usr/bin/env python3
import cv2
import numpy as np
import sys
def tile(img_in, img_size_mm, paper_size, paper_size_unit = "in", bgvalue = 255):
img_size = np.array(img_size_mm, dtype=np.float64) # w, h
paper_size = np.array(paper_size, dtype=np.float64) # w, h
if paper_size_unit == "in": paper_size *= 25.4
elif paper_size_unit != "mm":
raise Exception("Unknown paper unit size, use in or mm")
n_cols_rows = (paper_size // img_size).astype(np.uint64)
gaps = (paper_size % img_size) / (n_cols_rows + 1) # w_gap, h_gap
h, w, _ = img_in.shape # h, w
mm2px = h / img_size[1]
paper_size_px = (paper_size * mm2px).astype(np.uint64)
gaps_px = (gaps * mm2px).astype(int)
img_out = np.full(shape=(paper_size_px[1], paper_size_px[0], 3), fill_value = bgvalue, dtype = np.uint8)
cur_top = gaps_px[1]
for row in range(n_cols_rows[1]):
cur_left = gaps_px[0]
for col in range(n_cols_rows[0]):
img_out[cur_top : int(cur_top + h), cur_left : int(cur_left + w)] = img_in
cur_left += int(w + gaps_px[0])
cur_top += int(h + gaps_px[1])
return img_out
if __name__ == '__main__':
try:
input_name = sys.argv[1]
output_name = sys.argv[2]
input_size = sys.argv[3:5]
paper_size = sys.argv[5:7]
paper_size_unit = sys.argv[7] if len(sys.argv) > 7 else "in"
paper_bgvalue = sys.argv[8] if len(sys.argv) > 8 else 255
except Exception as e:
print(f"{sys.argv[0]} input.jpg output.jpg <input width mm> <input height mm> <paper width> <paper height> <paper unit (in or mm)> <fill value (0~255)>")
sys.exit(0)
img = cv2.imread(input_name)
img_t = tile(img, input_size, paper_size, paper_size_unit, paper_bgvalue)
cv2.imwrite(output_name, img_t)
Чтобы разложить нижеприведённую фотографию на лист размером 4 на 6 дюймов (варварство, но что я с ним могу сделать, разве что каждый раз умножать на 25.4... зато размеры исходника задаются только в миллиметрах!), и каждая напечатанная фотография была 30 на 40 мм, на чёрном фоне:
./tile.py input.jpg output.jpg 30 40 4 6 in 0
Результат


Полезная штука, особенно для виз
Минутка паранои: отправлять фото, да еще в формате "как на документы" непонятному телеграмм-боту ... На выходе владелец бота получает базу данных "эккаунт телеграмм - фотография", ну а дельше... сами додумайте кому и зачем может пригодится такая база)
try:
auth_data = validateand_extract_auth(Authorization, BOT_TOKEN)
except ValueError as e:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=f"Invalid auth data: {e}")
У FastApi есть механизм Depends, который решает эту задачу заметно удобнее – один раз прописываешь для роутера и дальше в каждой ручке внутри роутера будет проверка токена и уже готовый объект инит даты
Скрытый текст
def parse_init_data(init_data: str) -> TelegramInitData:
parsed_query = urllib.parse.parse_qs(init_data)
data = {}
for key in parsed_query:
data[key] = parsed_query[key][0]
data["user"] = json.loads(data["user"])
return TelegramInitData.validate(data)
def validate_telegram_data(query_string: str) -> bool:
data = dict(urllib.parse.parse_qsl(query_string))
received_hash = data.pop("hash", None)
if received_hash is None:
return False
data_check_string = "\n".join(
f"{key}={urllib.parse.unquote(value)}" for key, value in sorted(data.items())
)
secret_key = hmac.new(
key="WebAppData".encode("utf-8"),
msg=BOT_TOKEN.encode("utf-8"),
digestmod=hashlib.sha256,
).digest()
check_hash = hmac.new(
key=secret_key, msg=data_check_string.encode("utf-8"), digestmod=hashlib.sha256
).hexdigest()
return hmac.compare_digest(check_hash, received_hash)
async def decode_auth_header(request: Request):
expected_header = "authorization"
if expected_header not in request.headers:
raise HTTPException(status_code=401, detail="Authorization header is required")
token_encoded = request.headers[expected_header].removeprefix("TMA ")
token = base64.b64decode(token_encoded).decode()
if not validate_telegram_data(token):
raise HTTPException(status_code=401, detail="Invalid initData")
init_data = parse_init_data(token)
request.state.data = init_data
return init_dataМой пример инит дату в Base64 в Authorization: TMA .... передает, но думаю концепт понятен.
И пример испоьзования:
app.include_router(router, dependencies=[Depends(decode_auth_header)])
@router.post("/")
async def something(request: Request):
user_id = request.state.data.user.id
Делаем самые лучшие фото для документов