{"metadata":{"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":46105,"databundleVersionId":5087314,"sourceType":"competition"},{"sourceId":5600436,"sourceType":"datasetVersion","datasetId":3221731},{"sourceId":7139137,"sourceType":"datasetVersion","datasetId":4120147}],"dockerImageVersionId":30588,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"papermill":{"default_parameters":{},"duration":32.95045,"end_time":"2023-12-07T03:33:03.096120","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2023-12-07T03:32:30.145670","version":"2.4.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"**NOTE: This submission utilizes the maximum inference time limit, so depending on the situation, a submission scoring error may occur. \n\nHowever, you can succeed by trying multiple times.**","metadata":{"papermill":{"duration":0.005963,"end_time":"2023-12-07T03:32:40.573108","exception":false,"start_time":"2023-12-07T03:32:40.567145","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport pandas as pd\nimport json\nimport os\nfrom multiprocessing import cpu_count\n\ndef read_json_file(file_path):\n    \"\"\"Read a JSON file and parse it into a Python object.\n\n    Args:\n        file_path (str): The path to the JSON file to read.\n\n    Returns:\n        dict: A dictionary object representing the JSON data.\n        \n    Raises:\n        FileNotFoundError: If the specified file path does not exist.\n        ValueError: If the specified file path does not contain valid JSON data.\n    \"\"\"\n    try:\n        # Open the file and load the JSON data into a Python object\n        with open(file_path, 'r') as file:\n            json_data = json.load(file)\n        return json_data\n    except FileNotFoundError:\n        # Raise an error if the file path does not exist\n        raise FileNotFoundError(f\"File not found: {file_path}\")\n    except ValueError:\n        # Raise an error if the file does not contain valid JSON data\n        raise ValueError(f\"Invalid JSON data in file: {file_path}\")\n\ncpu_count()","metadata":{"execution":{"iopub.execute_input":"2023-12-07T03:32:40.584819Z","iopub.status.busy":"2023-12-07T03:32:40.584020Z","iopub.status.idle":"2023-12-07T03:32:47.911143Z","shell.execute_reply":"2023-12-07T03:32:47.910030Z"},"papermill":{"duration":7.33632,"end_time":"2023-12-07T03:32:47.914326","exception":false,"start_time":"2023-12-07T03:32:40.578006","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv('/kaggle/input/asl-signs/train.csv')\nprint(\"\\n\\n... LOAD SIGN TO PREDICTION INDEX MAP FROM JSON FILE ...\\n\")\ns2p_map = {k.lower():v for k,v in read_json_file(os.path.join(\"/kaggle/input/asl-signs/sign_to_prediction_index_map.json\")).items()}\np2s_map = {v:k for k,v in read_json_file(os.path.join(\"/kaggle/input/asl-signs/sign_to_prediction_index_map.json\")).items()}\nencoder = lambda x: s2p_map.get(x.lower())\ndecoder = lambda x: p2s_map.get(x)\n# print(s2p_map)\ntrain_df['label'] = train_df.sign.map(encoder)","metadata":{"execution":{"iopub.execute_input":"2023-12-07T03:32:47.926514Z","iopub.status.busy":"2023-12-07T03:32:47.925757Z","iopub.status.idle":"2023-12-07T03:32:48.196141Z","shell.execute_reply":"2023-12-07T03:32:48.194828Z"},"papermill":{"duration":0.279307,"end_time":"2023-12-07T03:32:48.198765","exception":false,"start_time":"2023-12-07T03:32:47.919458","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ROWS_PER_FRAME = 543\nMAX_LEN = 384\nCROP_LEN = MAX_LEN\nNUM_CLASSES  = 250\nPAD = -100.\nNOSE=[\n    1,2,98,327\n]\nLNOSE = [98]\nRNOSE = [327]\nLIP = [ 0, \n    61, 185, 40, 39, 37, 267, 269, 270, 409,\n    291, 146, 91, 181, 84, 17, 314, 405, 321, 375,\n    78, 191, 80, 81, 82, 13, 312, 311, 310, 415,\n    95, 88, 178, 87, 14, 317, 402, 318, 324, 308,\n]\nLLIP = [84,181,91,146,61,185,40,39,37,87,178,88,95,78,191,80,81,82]\nRLIP = [314,405,321,375,291,409,270,269,267,317,402,318,324,308,415,310,311,312]\n\nPOSE = [500, 502, 504, 501, 503, 505, 512, 513]\nLPOSE = [513,505,503,501]\nRPOSE = [512,504,502,500]\n\nREYE = [\n    33, 7, 163, 144, 145, 153, 154, 155, 133,\n    246, 161, 160, 159, 158, 157, 173,\n]\nLEYE = [\n    263, 249, 390, 373, 374, 380, 381, 382, 362,\n    466, 388, 387, 386, 385, 384, 398,\n]\n\nLHAND = np.arange(468, 489).tolist()\nRHAND = np.arange(522, 543).tolist()\n\nPOINT_LANDMARKS = LIP + LHAND + RHAND + NOSE + REYE + LEYE #+POSE\n\nNUM_NODES = len(POINT_LANDMARKS)\nCHANNELS = 6*NUM_NODES\n\nprint(NUM_NODES)\nprint(CHANNELS)\n\ndef tf_nan_mean(x, axis=0, keepdims=False):\n    return tf.reduce_sum(tf.where(tf.math.is_nan(x), tf.zeros_like(x), x), axis=axis, keepdims=keepdims) / tf.reduce_sum(tf.where(tf.math.is_nan(x), tf.zeros_like(x), tf.ones_like(x)), axis=axis, keepdims=keepdims)\n\ndef tf_nan_std(x, center=None, axis=0, keepdims=False):\n    if center is None:\n        center = tf_nan_mean(x, axis=axis,  keepdims=True)\n    d = x - center\n    return tf.math.sqrt(tf_nan_mean(d * d, axis=axis, keepdims=keepdims))\n\nclass Preprocess(tf.keras.layers.Layer):\n    def __init__(self, max_len=MAX_LEN, point_landmarks=POINT_LANDMARKS, **kwargs):\n        super().__init__(**kwargs)\n        self.max_len = max_len\n        self.point_landmarks = point_landmarks\n\n    def call(self, inputs):\n        if tf.rank(inputs) == 3:\n            x = inputs[None,...]\n        else:\n            x = inputs\n        \n        mean = tf_nan_mean(tf.gather(x, [17], axis=2), axis=[1,2], keepdims=True)\n        mean = tf.where(tf.math.is_nan(mean), tf.constant(0.5,x.dtype), mean)\n        x = tf.gather(x, self.point_landmarks, axis=2) #N,T,P,C\n        std = tf_nan_std(x, center=mean, axis=[1,2], keepdims=True)\n        \n        x = (x - mean)/std\n\n        if self.max_len is not None:\n            x = x[:,:self.max_len]\n        length = tf.shape(x)[1]\n        x = x[...,:2]\n\n        dx = tf.cond(tf.shape(x)[1]>1,lambda:tf.pad(x[:,1:] - x[:,:-1], [[0,0],[0,1],[0,0],[0,0]]),lambda:tf.zeros_like(x))\n\n        dx2 = tf.cond(tf.shape(x)[1]>2,lambda:tf.pad(x[:,2:] - x[:,:-2], [[0,0],[0,2],[0,0],[0,0]]),lambda:tf.zeros_like(x))\n\n        x = tf.concat([\n            tf.reshape(x, (-1,length,2*len(self.point_landmarks))),\n            tf.reshape(dx, (-1,length,2*len(self.point_landmarks))),\n            tf.reshape(dx2, (-1,length,2*len(self.point_landmarks))),\n        ], axis = -1)\n        \n        x = tf.where(tf.math.is_nan(x),tf.constant(0.,x.dtype),x)\n        \n        return x","metadata":{"execution":{"iopub.execute_input":"2023-12-07T03:32:48.210564Z","iopub.status.busy":"2023-12-07T03:32:48.209767Z","iopub.status.idle":"2023-12-07T03:32:48.241486Z","shell.execute_reply":"2023-12-07T03:32:48.240256Z"},"papermill":{"duration":0.039805,"end_time":"2023-12-07T03:32:48.243712","exception":false,"start_time":"2023-12-07T03:32:48.203907","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ECA(tf.keras.layers.Layer):\n    def __init__(self, kernel_size=5, **kwargs):\n        super().__init__(**kwargs)\n        self.supports_masking = True\n        self.kernel_size = kernel_size\n        self.conv = tf.keras.layers.Conv1D(1, kernel_size=kernel_size, strides=1, padding=\"same\", use_bias=False)\n\n    def call(self, inputs, mask=None):\n        nn = tf.keras.layers.GlobalAveragePooling1D()(inputs, mask=mask)\n        nn = tf.expand_dims(nn, -1)\n        nn = self.conv(nn)\n        nn = tf.squeeze(nn, -1)\n        nn = tf.nn.sigmoid(nn)\n        nn = nn[:,None,:]\n        return inputs * nn\n\nclass LateDropout(tf.keras.layers.Layer):\n    def __init__(self, rate, noise_shape=None, start_step=0, **kwargs):\n        super().__init__(**kwargs)\n        self.supports_masking = True\n        self.rate = rate\n        self.start_step = start_step\n        self.dropout = tf.keras.layers.Dropout(rate, noise_shape=noise_shape)\n      \n    def build(self, input_shape):\n        super().build(input_shape)\n        agg = tf.VariableAggregation.ONLY_FIRST_REPLICA\n        self._train_counter = tf.Variable(0, dtype=\"int64\", aggregation=agg, trainable=False)\n\n    def call(self, inputs, training=False):\n        x = tf.cond(self._train_counter < self.start_step, lambda:inputs, lambda:self.dropout(inputs, training=training))\n        if training:\n            self._train_counter.assign_add(1)\n        return x\n\nclass CausalDWConv1D(tf.keras.layers.Layer):\n    def __init__(self, \n        kernel_size=17,\n        dilation_rate=1,\n        use_bias=False,\n        depthwise_initializer='glorot_uniform',\n        name='', **kwargs):\n        super().__init__(name=name,**kwargs)\n        self.causal_pad = tf.keras.layers.ZeroPadding1D((dilation_rate*(kernel_size-1),0),name=name + '_pad')\n        self.dw_conv = tf.keras.layers.DepthwiseConv1D(\n                            kernel_size,\n                            strides=1,\n                            dilation_rate=dilation_rate,\n                            padding='valid',\n                            use_bias=use_bias,\n                            depthwise_initializer=depthwise_initializer,\n                            name=name + '_dwconv')\n        self.supports_masking = True\n        \n    def call(self, inputs):\n        x = self.causal_pad(inputs)\n        x = self.dw_conv(x)\n        return x\n\ndef Conv1DBlock(channel_size,\n          kernel_size,\n          dilation_rate=1,\n          drop_rate=0.0,\n          expand_ratio=2,\n          se_ratio=0.25,\n          activation='swish',\n          name=None):\n    '''\n    efficient conv1d block, @hoyso48\n    '''\n    if name is None:\n        name = str(tf.keras.backend.get_uid(\"mbblock\"))\n    # Expansion phase\n    def apply(inputs):\n        channels_in = tf.keras.backend.int_shape(inputs)[-1]\n        channels_expand = channels_in * expand_ratio\n\n        skip = inputs\n\n        x = tf.keras.layers.Dense(\n            channels_expand,\n            use_bias=True,\n            activation=activation,\n            name=name + '_expand_conv')(inputs)\n\n        # Depthwise Convolution\n        x = CausalDWConv1D(kernel_size,\n            dilation_rate=dilation_rate,\n            use_bias=False,\n            name=name + '_dwconv')(x)\n\n        x = tf.keras.layers.BatchNormalization(momentum=0.95, name=name + '_bn')(x)\n\n        x  = ECA()(x)\n\n        x = tf.keras.layers.Dense(\n            channel_size,\n            use_bias=True,\n            name=name + '_project_conv')(x)\n\n        if drop_rate > 0:\n            x = tf.keras.layers.Dropout(drop_rate, noise_shape=(None,1,1), name=name + '_drop')(x)\n\n        if (channels_in == channel_size):\n            x = tf.keras.layers.add([x, skip], name=name + '_add')\n        return x\n\n    return apply","metadata":{"execution":{"iopub.execute_input":"2023-12-07T03:32:48.255455Z","iopub.status.busy":"2023-12-07T03:32:48.255113Z","iopub.status.idle":"2023-12-07T03:32:48.281363Z","shell.execute_reply":"2023-12-07T03:32:48.280326Z"},"papermill":{"duration":0.035687,"end_time":"2023-12-07T03:32:48.284402","exception":false,"start_time":"2023-12-07T03:32:48.248715","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MultiHeadSelfAttention(tf.keras.layers.Layer):\n    def __init__(self, dim=256, num_heads=4, dropout=0, **kwargs):\n        super().__init__(**kwargs)\n        self.dim = dim\n        self.scale = self.dim ** -0.5\n        self.num_heads = num_heads\n        self.qkv = tf.keras.layers.Dense(3 * dim, use_bias=False)\n        self.drop1 = tf.keras.layers.Dropout(dropout)\n        self.proj = tf.keras.layers.Dense(dim, use_bias=False)\n        self.supports_masking = True\n\n    def call(self, inputs, mask=None):\n        qkv = self.qkv(inputs)\n        qkv = tf.keras.layers.Permute((2, 1, 3))(tf.keras.layers.Reshape((-1, self.num_heads, self.dim * 3 // self.num_heads))(qkv))\n        q, k, v = tf.split(qkv, [self.dim // self.num_heads] * 3, axis=-1)\n\n        attn = tf.matmul(q, k, transpose_b=True) * self.scale\n\n        if mask is not None:\n            mask = mask[:, None, None, :]\n\n        attn = tf.keras.layers.Softmax(axis=-1)(attn, mask=mask)\n        attn = self.drop1(attn)\n\n        x = attn @ v\n        x = tf.keras.layers.Reshape((-1, self.dim))(tf.keras.layers.Permute((2, 1, 3))(x))\n        x = self.proj(x)\n        return x\n\n\ndef TransformerBlock(dim=256, num_heads=4, expand=4, attn_dropout=0.2, drop_rate=0.2, activation='swish'):\n    def apply(inputs):\n        x = inputs\n        x = tf.keras.layers.BatchNormalization(momentum=0.95)(x)\n        x = MultiHeadSelfAttention(dim=dim,num_heads=num_heads,dropout=attn_dropout)(x)\n        x = tf.keras.layers.Dropout(drop_rate, noise_shape=(None,1,1))(x)\n        x = tf.keras.layers.Add()([inputs, x])\n        attn_out = x\n\n        x = tf.keras.layers.BatchNormalization(momentum=0.95)(x)\n        x = tf.keras.layers.Dense(dim*expand, use_bias=False, activation=activation)(x)\n        x = tf.keras.layers.Dense(dim, use_bias=False)(x)\n        x = tf.keras.layers.Dropout(drop_rate, noise_shape=(None,1,1))(x)\n        x = tf.keras.layers.Add()([attn_out, x])\n        return x\n    return apply","metadata":{"execution":{"iopub.execute_input":"2023-12-07T03:32:48.296906Z","iopub.status.busy":"2023-12-07T03:32:48.296351Z","iopub.status.idle":"2023-12-07T03:32:48.314670Z","shell.execute_reply":"2023-12-07T03:32:48.313684Z"},"papermill":{"duration":0.026725,"end_time":"2023-12-07T03:32:48.316826","exception":false,"start_time":"2023-12-07T03:32:48.290101","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_model(max_len=MAX_LEN, dropout_step=0, dim=192):\n    inp = tf.keras.Input((max_len,CHANNELS))\n    #x = tf.keras.layers.Masking(mask_value=PAD,input_shape=(max_len,CHANNELS))(inp) #we don't need masking layer with inference\n    x = inp\n    ksize = 17\n    x = tf.keras.layers.Dense(dim, use_bias=False,name='stem_conv')(x)\n    x = tf.keras.layers.BatchNormalization(momentum=0.95,name='stem_bn')(x)\n\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = TransformerBlock(dim,expand=2)(x)\n\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n    x = TransformerBlock(dim,expand=2)(x)\n\n    if dim == 384: #for the 4x sized model\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = TransformerBlock(dim,expand=2)(x)\n\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = Conv1DBlock(dim,ksize,drop_rate=0.2)(x)\n        x = TransformerBlock(dim,expand=2)(x)\n\n    x = tf.keras.layers.Dense(dim*2,activation=None,name='top_conv')(x)\n    x = tf.keras.layers.GlobalAveragePooling1D()(x)\n    x = LateDropout(0.8, start_step=dropout_step)(x)\n    x = tf.keras.layers.Dense(NUM_CLASSES,name='classifier')(x)\n    return tf.keras.Model(inp, x)","metadata":{"execution":{"iopub.execute_input":"2023-12-07T03:32:48.329180Z","iopub.status.busy":"2023-12-07T03:32:48.328219Z","iopub.status.idle":"2023-12-07T03:32:48.343621Z","shell.execute_reply":"2023-12-07T03:32:48.342549Z"},"papermill":{"duration":0.02396,"end_time":"2023-12-07T03:32:48.345912","exception":false,"start_time":"2023-12-07T03:32:48.321952","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models_path = [\n              '/kaggle/input/modelcv/islr-fp16-192-8-seed42-fold0-best.h5', #comment out other weights to check single model score\n               #'/kaggle/input/islr-models/islr-fp16-192-8-seed43-foldall-last.h5',\n               #'/kaggle/input/islr-models/islr-fp16-192-8-seed44-foldall-last.h5',\n               #'/kaggle/input/islr-models/islr-fp16-192-8-seed45-foldall-last.h5',\n              ]\nmodels = [get_model() for _ in models_path]\nfor model,path in zip(models,models_path):\n    model.load_weights(path)\nmodels[0].summary()","metadata":{"execution":{"iopub.execute_input":"2023-12-07T03:32:48.357600Z","iopub.status.busy":"2023-12-07T03:32:48.357082Z","iopub.status.idle":"2023-12-07T03:32:52.854081Z","shell.execute_reply":"2023-12-07T03:32:52.853040Z"},"papermill":{"duration":4.537334,"end_time":"2023-12-07T03:32:52.888477","exception":false,"start_time":"2023-12-07T03:32:48.351143","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class TFLiteModel(tf.Module):\n    \"\"\"\n    TensorFlow Lite model that takes input tensors and applies:\n        – a preprocessing model\n        – the ISLR model \n    \"\"\"\n\n    def __init__(self, islr_models):\n        \"\"\"\n        Initializes the TFLiteModel with the specified preprocessing model and ISLR model.\n        \"\"\"\n        super(TFLiteModel, self).__init__()\n\n        # Load the feature generation and main models\n        self.prep_inputs = Preprocess()\n        self.islr_models   = islr_models\n    \n    @tf.function(input_signature=[tf.TensorSpec(shape=[None, 543, 3], dtype=tf.float32, name='inputs')])\n    def __call__(self, inputs):\n        \"\"\"\n        Applies the feature generation model and main model to the input tensors.\n\n        Args:\n            inputs: Input tensor with shape [batch_size, 543, 3].\n\n        Returns:\n            A dictionary with a single key 'outputs' and corresponding output tensor.\n        \"\"\"\n        x = self.prep_inputs(tf.cast(inputs, dtype=tf.float32))\n        outputs = [model(x) for model in self.islr_models]\n        outputs = tf.keras.layers.Average()(outputs)[0]\n        return {'outputs': outputs}","metadata":{"execution":{"iopub.execute_input":"2023-12-07T03:32:52.925312Z","iopub.status.busy":"2023-12-07T03:32:52.924920Z","iopub.status.idle":"2023-12-07T03:32:52.934801Z","shell.execute_reply":"2023-12-07T03:32:52.933799Z"},"papermill":{"duration":0.030858,"end_time":"2023-12-07T03:32:52.936868","exception":false,"start_time":"2023-12-07T03:32:52.906010","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ROWS_PER_FRAME = 543  # number of landmarks per frame\ndef load_relevant_data_subset(pq_path):\n    data_columns = ['x', 'y', 'z']\n    data = pd.read_parquet('/kaggle/input/asl-signs/' + pq_path, columns=data_columns)\n    n_frames = int(len(data) / ROWS_PER_FRAME)\n    data = data.values.reshape(n_frames, ROWS_PER_FRAME, len(data_columns))\n    return data.astype(np.float32)","metadata":{"execution":{"iopub.execute_input":"2023-12-07T03:32:52.972041Z","iopub.status.busy":"2023-12-07T03:32:52.971705Z","iopub.status.idle":"2023-12-07T03:32:52.977918Z","shell.execute_reply":"2023-12-07T03:32:52.976795Z"},"papermill":{"duration":0.02611,"end_time":"2023-12-07T03:32:52.980023","exception":false,"start_time":"2023-12-07T03:32:52.953913","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tflite_keras_model = TFLiteModel(islr_models=models)\ndemo_output = tflite_keras_model(load_relevant_data_subset(train_df.path[0]))[\"outputs\"]\ndecoder(np.argmax(demo_output.numpy(), axis=-1))","metadata":{"execution":{"iopub.execute_input":"2023-12-07T03:32:53.015407Z","iopub.status.busy":"2023-12-07T03:32:53.014708Z","iopub.status.idle":"2023-12-07T03:32:59.515109Z","shell.execute_reply":"2023-12-07T03:32:59.513856Z"},"papermill":{"duration":6.520571,"end_time":"2023-12-07T03:32:59.517450","exception":false,"start_time":"2023-12-07T03:32:52.996879","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":" !pip install opencv-python","metadata":{"papermill":{"duration":0.016827,"end_time":"2023-12-07T03:32:59.552007","exception":false,"start_time":"2023-12-07T03:32:59.535180","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-12-07T10:47:29.364827Z","iopub.execute_input":"2023-12-07T10:47:29.365540Z","iopub.status.idle":"2023-12-07T10:47:42.016187Z","shell.execute_reply.started":"2023-12-07T10:47:29.365513Z","shell.execute_reply":"2023-12-07T10:47:42.015209Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\n\n# Try different camera indices if the default doesn't work\ncam_port = 3  # or 2, 3, etc.\ncam = cv2.VideoCapture(cam_port)\n\n# Check if the camera is opened successfully\nif not cam.isOpened():\n    print(f\"Error: Couldn't open camera at index {cam_port}\")\nelse:\n    # reading the input using the camera\n    result, image = cam.read()\n\n    # If the image is detected without any error, show the result\n    if result:\n        # showing result, it takes frame name and image output\n        cv2.imshow( image)\n\n        # saving the image in local storage\n        cv2.imwrite(image)\n\n        # If a keyboard interrupt occurs, destroy the image window\n        cv2.waitKey(0)\n        cv2.destroyAllWindows()\n\n    # If the captured image is corrupted, move to the else part\n    else:\n        print(\"No image detected. Please try again.\")\n","metadata":{"papermill":{"duration":0.01934,"end_time":"2023-12-07T03:32:59.590031","exception":false,"start_time":"2023-12-07T03:32:59.570691","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-12-07T11:59:26.035033Z","iopub.execute_input":"2023-12-07T11:59:26.035372Z","iopub.status.idle":"2023-12-07T11:59:26.043664Z","shell.execute_reply.started":"2023-12-07T11:59:26.035346Z","shell.execute_reply":"2023-12-07T11:59:26.042723Z"},"trusted":true},"execution_count":null,"outputs":[]}]}