{"cells":[{"metadata":{},"cell_type":"markdown","source":"fork of https://www.kaggle.com/mistag/global-wheat-to-tfrecords\n\nchange - make the source_id numeric","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":false},"cell_type":"markdown","source":"## Create TFRecords\nSo we will convert the Global Wheat Detection dataset to TFRecords, for use in TensorFlow-based models.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport os, ast, glob\nfrom PIL import Image, ImageFont, ImageDraw\nimport hashlib\nfrom io import BytesIO\nfrom tqdm import tqdm\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Read annotation data","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"LABEL='Wheat'\ndf=pd.read_csv(\"/kaggle/input/global-wheat-detection/train.csv\")\ndf.bbox = df.bbox.apply(ast.literal_eval)\nfor i in range(len(df)):\n    df.bbox.iloc[i][2]=df.bbox.iloc[i][0]+df.bbox.iloc[i][2]\n    df.bbox.iloc[i][3]=df.bbox.iloc[i][1]+df.bbox.iloc[i][3]\ndf.sample(5)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## TFRecords creation\nThe function below creates TFRecords with all the bells and whistles.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def create_tf_example(imagedf, longest_edge=1024, source_id=0):  \n    fname = '/kaggle/input/global-wheat-detection/train/'+imagedf.image_id.iloc[0]+'.jpg'\n    filename=fname.split('/')[-1] # exclude path\n    img = Image.open(fname, \"r\")\n    # resize image if larger that longest edge while keeping aspect ratio\n    if max(img.size) > longest_edge:\n        img.thumbnail((longest_edge, longest_edge), Image.ANTIALIAS)\n    height = img.size[1] # Image height\n    width = img.size[0] # Image width\n    buf= BytesIO()\n    img.save(buf, format= 'JPEG') # encode to jpeg in memory\n    encoded_image_data= buf.getvalue()\n    image_format = b'jpeg'\n    source_id = str(source_id) # must be unique number\n    # A hash of the image is used in some frameworks\n    key = hashlib.sha256(encoded_image_data).hexdigest()   \n    # object bounding boxes \n    boxes = np.array(imagedf['bbox'].tolist())\n    xmins = boxes[:,0]/width # List of normalized left x coordinates in bounding box (1 per box)\n    ymins = boxes[:,1]/height # List of normalized top y coordinates in bounding box (1 per box)\n    xmaxs = boxes[:,2]/width # List of normalized right x coordinates in bounding box\n    ymaxs = boxes[:,3]/height # List of normalized bottom y coordinates in bounding box\n    # List of string class name & id of bounding box (1 per box)\n    object_cnt = len(imagedf)\n    classes_text = []\n    classes = []\n    cname = LABEL\n    for i in range(object_cnt):\n        classes_text.append(cname.encode())\n        classes.append(1)\n    # unused features from Open Image \n    depiction = np.zeros(object_cnt, dtype=int)\n    group_of = np.zeros(object_cnt, dtype=int)\n    occluded = np.zeros(object_cnt, dtype=int) #also Pascal VOC\n    truncated = np.zeros(object_cnt, dtype=int) # also Pascal VOC\n    # Pascal VOC\n    view_text = []\n    for i in range(object_cnt):\n        view_text.append('frontal'.encode())\n    difficult = np.zeros(object_cnt, dtype=int)\n\n    tf_record = tf.train.Example(features=tf.train.Features(feature={\n        'image/height': tf.train.Feature(int64_list=tf.train.Int64List(value=[height])),\n        'image/width': tf.train.Feature(int64_list=tf.train.Int64List(value=[width])),\n        'image/filename': tf.train.Feature(bytes_list=tf.train.BytesList(value=[filename.encode()])),\n        'image/source_id': tf.train.Feature(bytes_list=tf.train.BytesList(value=[source_id.encode()])),\n        'image/encoded': tf.train.Feature(bytes_list=tf.train.BytesList(value=[encoded_image_data])),\n        'image/key/sha256': tf.train.Feature(bytes_list=tf.train.BytesList(value=[key.encode()])),\n        'image/format': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_format])),\n        'image/object/bbox/xmin': tf.train.Feature(float_list=tf.train.FloatList(value=xmins)),\n        'image/object/bbox/xmax': tf.train.Feature(float_list=tf.train.FloatList(value=xmaxs)),\n        'image/object/bbox/ymin': tf.train.Feature(float_list=tf.train.FloatList(value=ymins)),\n        'image/object/bbox/ymax': tf.train.Feature(float_list=tf.train.FloatList(value=ymaxs)),\n        'image/object/class/text': tf.train.Feature(bytes_list=tf.train.BytesList(value=classes_text)),\n        'image/object/class/label': tf.train.Feature(int64_list=tf.train.Int64List(value=classes)),\n        'image/object/depiction': tf.train.Feature(int64_list=tf.train.Int64List(value=depiction)),\n        'image/object/group_of': tf.train.Feature(int64_list=tf.train.Int64List(value=group_of)),\n        'image/object/occluded': tf.train.Feature(int64_list=tf.train.Int64List(value=occluded)),\n        'image/object/truncated': tf.train.Feature(int64_list=tf.train.Int64List(value=truncated)),\n        'image/object/difficult': tf.train.Feature(int64_list=tf.train.Int64List(value=difficult)),\n        'image/object/view': tf.train.Feature(bytes_list=tf.train.BytesList(value=view_text))\n    }))\n    return tf_record","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We also need a labels.pbtxt file with the labels (only one).","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"labels=[LABEL]\npbfile=open('./labels.pbtxt', 'w') \nfor i in range (len(labels)): \n    pbfile.write('item {{\\n id: {}\\n name:\\'{}\\'\\n}}\\n\\n'.format(i+1, labels[i])) \npbfile.close()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Helper functions\nA few helper functions are defined below for visualizing images.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def bbox(img, xmin, ymin, xmax, ymax, color, width):\n    draw = ImageDraw.Draw(img)\n    xres, yres = img.size[0], img.size[1]\n    box = np.multiply([xmin, ymin, xmax, ymax], [xres, yres, xres, yres]).astype(int).tolist()\n    draw.rectangle(box, outline=color, width=width)\n           \ndef plot_img(img, axes, xmin, ymin, xmax, ymax, classes, class_label, by):\n    for i in range(len(xmin)):\n        #color=hex_to_rgb(colors[class_label[i]-1])\n        color='#e81123'\n        bbox(img, xmin[i], ymin[i], xmax[i], ymax[i], color, 5)\n    plt.setp(axes, xticks=[], yticks=[])\n    axes.set_title(by)\n    plt.imshow(img)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Create sharded TFRecords\nWe create a sharded dataset here, 20 shards will give a granularity of 5% for train/validate split.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"%%time\nimport contextlib2\n\nfilelist = glob.glob('/kaggle/input/global-wheat-detection/train/*')\n\ndef open_sharded_tfrecords(exit_stack, base_path, num_shards):\n    tf_record_output_filenames = [\n        '{}-{:04d}-of-{:04d}.tfrecord'.format(base_path, idx, num_shards)\n        for idx in range(num_shards)\n        ]\n    tfrecords = [\n        exit_stack.enter_context(tf.io.TFRecordWriter(file_name))\n        for file_name in tf_record_output_filenames\n    ]\n    return tfrecords\n\nnum_shards=20\noutput_filebase='./Wheat'\n\n# A context2.ExitStack is used to automatically close all the TFRecords created \nwith contextlib2.ExitStack() as tf_record_close_stack:\n    output_tfrecords = open_sharded_tfrecords(tf_record_close_stack, output_filebase, num_shards)\n    for i in tqdm(range(len(filelist))):\n        fid = filelist[i].replace('/kaggle/input/global-wheat-detection/train/','').split('.')[0]\n        ldf=df[df.image_id == fid].reset_index()\n        if len(ldf) > 0:\n            tf_record = create_tf_example(ldf, longest_edge=1024, source_id=i)\n            output_shard_index = i % num_shards\n            output_tfrecords[output_shard_index].write(tf_record.SerializeToString())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Check the output\nThe last step is to check a few records to see that everything went OK:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"fname='./Wheat-0005-of-0020.tfrecord'\ndataset3 = tf.data.TFRecordDataset(fname)\nfig = plt.figure(figsize=(12,18))\nidx=1\nfor raw_record in dataset3.take(6):\n    axes = fig.add_subplot(3, 2, idx)\n    example = tf.train.Example()\n    example.ParseFromString(raw_record.numpy())\n    xmin=example.features.feature['image/object/bbox/xmin'].float_list.value[:]\n    xmax=example.features.feature['image/object/bbox/xmax'].float_list.value[:]\n    ymin=example.features.feature['image/object/bbox/ymin'].float_list.value[:]\n    ymax=example.features.feature['image/object/bbox/ymax'].float_list.value[:]\n    classes=example.features.feature['image/object/class/text'].bytes_list.value[:]\n    class_label=example.features.feature['image/object/class/label'].int64_list.value[:]\n    img_encoded=example.features.feature['image/encoded'].bytes_list.value[0]\n    img = Image.open(BytesIO(img_encoded))\n    plot_img(img, axes, xmin, ymin, xmax, ymax, classes, class_label, '')\n    idx=idx+1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Yup - everything OK!","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}