Asosiy qismga o'tish

Bozor va narx: bitta kamera qancha turadi

25-bob 5 kod bloki 3163 so'z

Bu bobning kodi: kod/25_narx.py — kitob papkasidan ishga tushiring: python kod/25_narx.py

Mijoz birinchi bo'lib "qancha turadi?" deb so'raydi. Javob ikki tomondan quriladi: tannarx — bizga bitta kamera oyiga qanchaga tushadi, va qiymat — mijoz nima uchun pul to'laydi. Bu bobda tannarxni o'lchaymiz, taxmin qilmaymiz: 22-bobdagi kaska tizimi bitta kompyuterda nechta kamerani ko'taradi, qancha quvvat oladi va O'zbekistondagi narxlarda bu qanchaga tushadi.

Narxlar 2026-09-22 holatida: uskuna — asaxiy.uz, dollar kursi — Markaziy bank, elektr tarifi — Vazirlar Mahkamasining 2026-05-15 dagi 243-son qarori. Narxlar o'zgaradi — hisob-kitob kodi shuning uchun parametrlar bilan yozilgan.

Nega 18-bobdagi raqam yaramaydi

18-bobda bitta kompyuter ~70 ta kamerani 15 fps da ko'tardi. U odam aniqlash uchun edi: YOLO11n, 384x640, TensorRT, katta batch. 22-bobdagi kaska quvuri boshqa ish qiladi:

  1. 2560x1440 kadrni dekodlaydi;
  2. odamlarni 1280 da qidiradi (kichik odam ham ko'rinsin, 17-bob);
  3. BoT-SORT bilan kuzatadi, kamera harakatini (GMC) hisobga olib;
  4. har bir odam uchun asl kadrdan qirqim olib, kaska modelini ishlatadi.

Narx vazifaga bog'liq: "nechta odam o'tdi" va "kim kaskasiz" — bir xil kamera, lekin tannarxi boshqa. Shuning uchun aynan sotiladigan quvurni o'lchaymiz.

Yuklama sinovi

Ishchi 22-bobdagi quvurni oladi (kaskasizmi — 22-bobdan), faqat kadrni RTSP dan emas, videofayldan o'qiydi va iloji boricha tez ishlaydi. Har bir bosqich vaqtini alohida sanaydi. Bir nechta ishchini bir vaqtda boshlash uchun u "tayyor" deb yozib, buyruq kutadi — shunda hamma ishchi o'lchovni bir paytda boshlaydi.

kod/25_yuklama.pyyangi fayl
python66 qator
# Yuklama ishchisi: 22-bobdagi kaska quvuri videofayldan, iloji boricha tez. "tayyor" dan keyin Enter kutadi,
# --soniya davomida kadrlarni sanaydi va JSON chiqaradi (kadr/s va har bosqich uchun ms).
import argparse
import json
import os
import sys
import time

import cv2

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from ultralytics import YOLO  # noqa: E402
from ultralytics.trackers import BOTSORT  # noqa: E402
from ultralytics.utils import LOGGER, YAML, IterableSimpleNamespace  # noqa: E402
from ultralytics.utils.checks import check_yaml  # noqa: E402

LOGGER.setLevel("ERROR")
kaskasizmi = __import__("22_qurilish_ishchi").kaskasizmi


def main():
    p = argparse.ArgumentParser()
    p.add_argument("--video", default="datasets/pexels/13921040_2560x1440.mp4")
    p.add_argument("--gmc", default="sparseOptFlow", help="none — qo'zg'almas kamera")
    p.add_argument("--soniya", type=float, default=15)
    p.add_argument("--qizdirish", type=int, default=20, help="o'lchovdan oldingi kadrlar")
    a = p.parse_args()
    odam, ppe = YOLO("weights/yolo11n.pt"), YOLO("out/train/ppe_coco/weights/best.pt")
    sozlama = YAML.load(check_yaml("botsort.yaml")) | {"gmc_method": a.gmc}
    tracker = BOTSORT(IterableSimpleNamespace(**sozlama), frame_rate=30)
    video = cv2.VideoCapture(a.video)
    vaqt = dict.fromkeys(("dekod", "aniqlash", "trek", "kaska"), 0.0)

    def qadam():
        t = [time.perf_counter()]
        ok, rasm = video.read()
        if not ok:
            video.set(cv2.CAP_PROP_POS_FRAMES, 0)
            ok, rasm = video.read()
        t.append(time.perf_counter())
        r = odam.predict(rasm, imgsz=1280, classes=[0], conf=0.1, device=0, verbose=False)[0]
        t.append(time.perf_counter())
        treklar = tracker.update(r.boxes.cpu().numpy(), rasm)
        t.append(time.perf_counter())
        kaskasizmi(ppe, rasm, treklar)
        t.append(time.perf_counter())
        for k, boshi, oxiri in zip(vaqt, t, t[1:]):
            vaqt[k] += oxiri - boshi
        return len(treklar)

    for _ in range(a.qizdirish):
        qadam()
    vaqt.update(dict.fromkeys(vaqt, 0.0))
    print("tayyor", flush=True)
    sys.stdin.readline()
    kadr = odamlar = 0
    t0 = time.time()
    while time.time() - t0 < a.soniya:
        odamlar += qadam()
        kadr += 1
    print(json.dumps({"fps": round(kadr / (time.time() - t0), 2), "odam": round(odamlar / kadr, 1),
                      **{k: round(v * 1000 / kadr, 1) for k, v in vaqt.items()}}), flush=True)


if __name__ == "__main__":
    main()

Boshqaruvchi 1, 2, 3, 4, 5, 6 va 8 ta ishchini ishga tushiradi — har ishchi bitta kamera o'rnida — va o'lchov davomida GPU quvvati, bandligi va xotirasini nvidia-smi dan (har 0.5 soniyada), CPU bandligini psutil dan oladi. Ikki holat: kamera harakatini hisobga olish (GMC) yoqilgan — 22-bobdagidek, va o'chirilgan — qo'zg'almas kamera uchun. Avval hech narsa ishlamaganda o'lchaymiz: GPU da boshqa ish ham bo'lishi mumkin (monitor, boshqa dasturlar).

kod/25_narx.pyyangi fayl · 1-qator: from kitob_yordam import fig, show
python59 qator
import json
import math
import subprocess
import sys
import time

import pandas as pd
import psutil

SMI = ["nvidia-smi", "--query-gpu=power.draw,utilization.gpu,memory.used", "--format=csv,noheader,nounits", "-lms", "500"]


def olcha(ish):
    """ish() davomida: GPU quvvati (W), bandligi (%), xotirasi (MB) — o'rtacha; CPU bandligi (%)."""
    smi = subprocess.Popen(SMI, stdout=subprocess.PIPE, text=True)
    psutil.cpu_percent()
    natija = ish()
    cpu = psutil.cpu_percent()
    smi.terminate()
    q = [list(map(float, s.split(","))) for s in smi.communicate()[0].splitlines()[2:] if s.strip()]
    return natija, cpu, [sum(x[i] for x in q) / len(q) for i in range(3)]


def yuklama(k, gmc):
    ishchilar = [subprocess.Popen([sys.executable, "kod/25_yuklama.py", "--gmc", gmc], stdin=subprocess.PIPE,
                                  stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True) for _ in range(k)]
    try:
        for w in ishchilar:
            if w.stdout.readline().strip() != "tayyor":
                raise RuntimeError("ishchi ishga tushmadi")

        def ish():
            for w in ishchilar:
                w.stdin.write("\n")
                w.stdin.flush()
            return [json.loads(w.stdout.readline()) for w in ishchilar]

        return olcha(ish)
    finally:
        for w in ishchilar:
            w.kill()


_, cpu, (vatt, gpu, xotira) = olcha(lambda: time.sleep(10))
qatorlar = [{"GMC": "bo'sh", "ishchi": 0, "jami fps": 0, "fps / ishchi": 0, "CPU %": round(cpu), "GPU %": round(gpu),
             "GPU W": round(vatt), "GPU xotira, GB": round(xotira / 1024, 1)}]
bosqichlar = {}
for gmc in ("sparseOptFlow", "none"):
    for k in (1, 2, 3, 4, 5, 6, 8):
        r, cpu, (vatt, gpu, xotira) = yuklama(k, gmc)
        jami = sum(x["fps"] for x in r)
        qatorlar.append({"GMC": gmc, "ishchi": k, "jami fps": round(jami, 1), "fps / ishchi": round(jami / k, 1),
                         "CPU %": round(cpu), "GPU %": round(gpu), "GPU W": round(vatt),
                         "GPU xotira, GB": round(xotira / 1024, 1)})
        if k == 1:
            bosqichlar[gmc] = {x: r[0][x] for x in ("dekod", "aniqlash", "trek", "kaska")} | {"odam / kadr": r[0]["odam"]}
jadval = pd.DataFrame(qatorlar)
show(jadval, n=20)
show(pd.DataFrame(bosqichlar).T.rename_axis("GMC").reset_index())
GMCishchijami fpsfps / ishchiCPU %GPU %GPU WGPU xotira, GB
bo'sh00028281
sparseOptFlow116.316.31627882.9
sparseOptFlow223.511.831491194.6
sparseOptFlow326.48.843601326.5
sparseOptFlow429.87.556661428
sparseOptFlow533.16.667721519.5
sparseOptFlow633.95.7807415410.9
sparseOptFlow836.24.5997815813.8
none123.223.217371132.8
none231.815.932621414.6
none334.911.645721526.2
none435.88.956781587.9
none537.87.668831659.4
none638.46.4808416611
none839.85998617014
GMCdekodaniqlashtrekkaskaodam / kadr
sparseOptFlow2.98.818.431.215
none2.59.21.43014.4

Jadvallarni o'qiymiz:

  • Bitta ishchi GMC bilan 16.3 fps, GMCsiz 23.2 fps beradi. Bu — quvurning o'z tezligi, kadr fayldan keladi. Real tizimda bunga RTSP oqimi, API ga yuborish va boshqa jarayonlar qo'shiladi, shuning uchun bu yerdagi sig'im — yuqori chegara.
  • Cheklov protsessorda. Ishchilar ko'paygan sari jami fps o'sadi, lekin sekinlashib boradi: 8 ishchida CPU 99%, GPU esa 78–86%. Bu kompyuterda WSL ga protsessorning 32 ta ipidan 8 tasi berilgan (Intel: 24 yadro, 32 ip) — butun protsessorli Linux server ko'proq ko'taradi. Buni o'z serveringizda o'lchang.
  • GPU xotirasi: har ishchi taxminan 1.6–1.9 GB oladi (bo'sh holatda 1.0 GB, 8 ishchida 13.8–14 GB). 16 GB li karta ~8 ishchini sig'diradi, 8 GB li — yarmini.
  • Bosqichlar: kaska tekshiruvi kadr vaqtining yarmini (GMC bilan) va 70% ini (GMCsiz) oladi — kadrda ~15 odam, har biriga ~2 ms. Demak, tannarx kadrdagi odamlar soniga bog'liq: gavjum maydon qimmatroq. GMC ~17 ms protsessor vaqti oladi — qo'zg'almas kamerada uni o'chirish mumkin. Dekodlash atigi 2.5–2.9 ms: bu vazifada 18-bobdagi NVDEC katta yutuq bermaydi.

Bitta kompyuter nechta kamera

Kaska uchun har kameraga qancha fps kerak? 22-bobdagi jonli tizim 6.7 fps da ishladi va signallarni to'g'ri berdi. Undan pastini sinamadik, shuning uchun talabni 7 fps deb olamiz. Sig'im — har bir ishchi kamida 7 fps olgan eng ko'p ishchi soni:

kod/25_narx.pydavomi
python7 qator
KAMERA_FPS = 7
sigim, quvvat = {}, {}
for gmc, g in jadval[jadval.ishchi > 0].groupby("GMC", sort=False):
    mos = g[g["fps / ishchi"] >= KAMERA_FPS]
    sigim[gmc] = int(mos.ishchi.max())
    quvvat[gmc] = int(mos.loc[mos.ishchi.idxmax(), "GPU W"])
    print(f"GMC={gmc}: {sigim[gmc]} kamera, GPU {quvvat[gmc]} W")
Chiqish
GMC=sparseOptFlow: 4 kamera, GPU 142 W
GMC=none: 5 kamera, GPU 165 W

Kaska nazorati uchun bitta kompyuter 4 ta (harakatlanuvchi kamera) yoki 5 ta (qo'zg'almas kamera) kamerani ko'taradi. 18-bobdagi 70 bilan solishtiring: bir xil kompyuter, bir xil model oilasi, vazifa boshqa — sig'im o'n baravardan ko'p farq qiladi.

Tannarx: kamera boshiga oyiga

Server — o'lchov o'tkazilgan kompyuterning qismlari, asaxiy.uz narxlarida. Kamera — 4 MP (2560x1440) IP kamera: 17-bob bo'yicha kaska uchun shu o'lcham kerak. Protsessorning quvvatini WSL ichidan o'lchab bo'lmaydi — Intel ning rasmiy "Processor Base Power" qiymatini olamiz; bu taxmin. Uskuna 36 oyda o'zini qoplashi kerak deb hisoblaymiz — bu ham qaror, qonun emas.

kod/25_narx.pydavomi
python18 qator
USD = 11_809.82                            # Markaziy bank kursi, 2026-09-22
TARIF = 1_100                              # so'm / kVt·soat, VMQ 243-son (2026-05-15), 2026-06-01 dan
CPU_W = 125                                # i9-14900K "Processor Base Power" (Intel) — o'lchanmagan, taxmin
OY_SOAT = 730
MUDDAT_OY = 36
SERVER = {"RTX 5070 Ti 16 GB (ASUS ProArt)": 16_119_000, "Intel Core i9-14900K": 6_249_000,
          "ona plata Z790": 2_629_000, "64 GB DDR5 (2 x 32 GB)": 2 * 1_829_000, "1 TB NVMe SSD": 799_000,
          "850 W quvvat bloki": 869_000, "korpus": 709_000, "sovutgich": 559_000}
KAMERA = 889_000                           # Hikvision DS-2CD2143G0-I, 4 MP
server = sum(SERVER.values())
print(f"server: {server:,} so'm (~{server / USD:,.0f} $)".replace(",", " "))

tannarx = {}
for gmc, n in sigim.items():
    qism = {"server ulushi": server / MUDDAT_OY / n, "kamera": KAMERA / MUDDAT_OY,
            "elektr": (quvvat[gmc] + CPU_W) * OY_SOAT / 1000 * TARIF / n}
    tannarx[gmc] = qism | {"jami": sum(qism.values())}
show(pd.DataFrame(tannarx).T.round(-3).astype(int).rename_axis("so'm / kamera / oy").reset_index())
Chiqish
server: 31 591 000 so'm (~2 675 $)
so'm / kamera / oyserver ulushikameraelektrjami
sparseOptFlow219 00025 00054 000298 000
none176 00025 00047 000247 000

Server 31.6 mln so'm (~2 675 $). Kamera boshiga oyiga ~298 ming so'm (GMC bilan) va ~247 ming so'm (GMCsiz). Ulushning 70% dan ko'prog'i — server, ya'ni sig'im: har qo'shimcha kamera server ulushini kamaytiradi. Elektr — 54 va 47 ming so'm; protsessor quvvati taxmin bo'lgani uchun bu eng noaniq qator. Kameraning o'zi — 25 ming so'm. Tannarxga ish kirmagan: o'rnatish, sozlash, qo'llab-quvvatlash — ularni o'z soatbay narxingiz bilan qo'shing (3-mashq). Litsenziya ham kirmagan: AGPL yo'lida u nol, Enterprise yo'lida — Ultralytics aytadigan narx, Apache modeliga o'tishda — qayta o'qitish ishi (23-bob).

Narx modellari

Tannarx — pastki chegara. Ustiga o'rnatish, qo'llab-quvvatlash ishi va foyda qo'shiladi. Uchta keng tarqalgan model:

  1. Bir martalik sotuv. Mijoz uskuna, o'rnatish va litsenziya uchun bir marta to'laydi, keyin yillik qo'llab-quvvatlash shartnomasi. Uskuna mijozniki, pul boshida keladi. Kod mijozga beriladi — 23-bobdagi AGPL masalasi aynan shu yerda.
  2. Oylik obuna (kamera boshiga). Uskuna bizniki, mijoz har oy to'laydi. Mijozga kirish oson, bizga — pul sekin qaytadi va uskunaning xavfi bizda.
  3. Aralash. Uskuna bir martalik, dastur va qo'llab-quvvatlash — oylik.

Obuna modelida asosiy savol: uskuna necha oyda qaytadi? 8 kamerali qurilish maydoni uchun, obuna narxi tannarxning bir necha baravari bo'lsa:

kod/25_narx.pydavomi
python13 qator
MAYDON = 8
for gmc, n in sigim.items():
    serverlar = math.ceil(MAYDON / n)
    uskuna = serverlar * server + MAYDON * KAMERA
    elektr_oy = tannarx[gmc]["elektr"] * MAYDON
    satrlar = []
    for k in (1.5, 2, 3):
        narx = tannarx[gmc]["jami"] * k
        satrlar.append({"narx / tannarx": k, "so'm / kamera / oy": round(narx, -3),
                        "maydon, so'm / oy": round(narx * MAYDON, -3),
                        "uskuna qaytadi, oy": round(uskuna / (narx * MAYDON - elektr_oy), 1)})
    print(f"GMC={gmc}: {serverlar} server, uskuna {uskuna:,} so'm".replace(",", " "))
    show(pd.DataFrame(satrlar))
Chiqish
GMC=sparseOptFlow: 2 server  uskuna 70 294 000 so'm
GMC=none: 2 server  uskuna 70 294 000 so'm
narx / tannarxso'm / kamera / oymaydon, so'm / oyuskuna qaytadi, oy
1.5447 0003 572 00022.4
2595 0004 763 00016.2
3893 0007 144 00010.5
narx / tannarxso'm / kamera / oymaydon, so'm / oyuskuna qaytadi, oy
1.5370 0002 961 00027.2
2494 0003 948 00019.7
3740 0005 923 00012.7

Server butun son bo'lib sotiladi: 8 kamera uchun ikkala holatda ham 2 ta server kerak. GMCsiz holatda ikkinchi server to'liq band emas — kamera boshiga tannarx kichikroq, lekin maydon uchun uskuna bir xil, shuning uchun uskuna sekinroq qaytadi. Obuna tannarxning 1.5 baravari bo'lsa, uskuna 22–27 oyda qaytadi — 36 oylik muddatga yaqin: mijoz ikkinchi yili ketsa, zarar. 3 baravarida — 10.5–12.7 oyda. Qisqa loyiha (bitta qurilish — bir-ikki yil) uchun bir martalik yoki aralash model xavfsizroq; uzoq mijoz uchun — obuna.

Mijoz nima uchun to'laydi

Qonuniy majburiyat. 24-bobda ko'rdik: ish beruvchi himoya vositalarisiz xodimni ishdan chetlashtirishi shart (MK 151) va ish joyidagi sharoit ustidan nazorat qilishi shart (MK 359). O'sha 359-modda ish beruvchidan "mehnatni muhofaza qilish xizmatini ... tashkil etishi"ni ham talab qiladi — mijoz tomonida tizimdan foydalanuvchi va ko'pincha qaror qiluvchi aynan shu xizmat. Bu majburiyat faqat qurilishga emas, har bir ish beruvchiga tegishli: zavod, ombor, kon — bir xil mantiq.

Jarima. MJtK 49-moddasi: mansabdor shaxs tomonidan mehnat va mehnatni muhofaza qilish qonunchiligini buzish — BHM ning 5–10 baravari (2.2–4.4 mln so'm), bir yil ichida takrorlansa — 10–15 baravari (4.4–6.6 mln so'm). Taqqoslang: 8 kamerali maydon tannarxning 2 baravarida oyiga ~4.8 mln so'm. Lekin jarima faqat tekshiruvda chiqadi — narxni u bilan asoslash zaif. Asosiy qiymat — baxtsiz hodisaning oldini olish, uning narxini (davolash, ish to'xtashi, sud) esa mijozning o'zi biladi: pilotda so'rang va yozib oling.

Signal sifati. Mijoz kamera uchun emas, to'g'ri signal uchun to'laydi. 22-bobda tasdiqsiz tizim 20 soniyada 91 ta signal berdi — bunday tizim birinchi haftadayoq o'chiriladi. Tasdiq bilan — 6 ta. Shuning uchun narx pilot natijasiga bog'lanadi: qabul qilish mezonlari 26-bobda.

Asosiy fikr

  • Tannarx vazifaga bog'liq: odam sanash uchun bitta kompyuter ~70 kamera (18-bob), kaska nazorati uchun — 4–5 ta.
  • Bu kompyuterda cheklov — protsessor, GPU emas; kaska tekshiruvi kadr vaqtining yarmidan ko'pini oladi va kadrdagi odamlar soniga bog'liq.
  • Kamera boshiga oylik tannarx ~250–300 ming so'm, uning 70% dan ko'prog'i — server. Sig'imni oshirish — tannarxni kamaytirishning asosiy yo'li.
  • Serverlar butun son: maydonning kamera soni va server sig'imi mos kelmasa, uskuna sekin qaytadi.
  • Narx modeli loyiha muddatiga mos bo'lsin: qisqa loyiha — bir martalik yoki aralash, uzoq mijoz — obuna.

Mashqlar

  1. Kaska tekshiruvi eng qimmat bosqich. Uni har kadrda emas, har bir trek uchun har 3-kadrda qiling va yuklama sinovini takrorlang. Sig'im va tannarx qancha o'zgaradi? 22-bobdagi signallar jadvali o'zgarmaganini tekshiring.
  2. Yuklama sinovini maqsadli serveringizda (butun protsessorli Linux yoki arzonroq GPU, masalan 8 GB li) o'tkazing va SERVER narxlarini almashtiring. GPU xotirasi nechta ishchiga yetadi?
  3. Tannarxga ishni qo'shing: o'rnatish soatlari (bir marta) va oylik qo'llab-quvvatlash soatlari, o'z soatbay narxingiz bilan. 8 kamerali, 18 oylik qurilish loyihasi uchun uch modelning qaysi biri sizga va mijozga foydaliroq?

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar