├── .gitignore ├── results ├── object_counts_per_interval.csv ├── objects_over_time_d.png ├── objects_by_class_over_time.png ├── object_counts_by_class_per_interval.csv └── predictions.csv ├── requirements.txt ├── LICENSE ├── README.md └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /results/object_counts_per_interval.csv: -------------------------------------------------------------------------------- 1 | minutes,0 2 | 0:00,21 3 | 5:00,29 4 | 10:00,19 5 | 15:00,39 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib==3.7.1 2 | opencv_python==4.7.0.72 3 | pandas==2.0.2 4 | Requests==2.31.0 5 | -------------------------------------------------------------------------------- /results/objects_over_time_d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboflow/inference-dashboard-example/HEAD/results/objects_over_time_d.png -------------------------------------------------------------------------------- /results/objects_by_class_over_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roboflow/inference-dashboard-example/HEAD/results/objects_by_class_over_time.png -------------------------------------------------------------------------------- /results/object_counts_by_class_per_interval.csv: -------------------------------------------------------------------------------- 1 | minutes,AB Bohne,BM Bohne,BM Gemahlen,BW Bohne,BW Gemahlen,Barista CB,Barista CC,CC Vollmundig 36Pads,CFino Bohne,Colombia BBBohne,Colombia BBGemahlen,Discount Price,Empty Shelf,Espresso Aromatisch,Espresso Kraftig,FM 36Pads,FM Bohne,LG Gemahlen,Price,SM Gemahlen,Simo EsElegant,Simo EsKraft,Simo KaffeeBW,Simo KaffeeKraft,Simo KaffeeMild 2 | 0:00,0,0,1,0,2,1,1,2,0,0,0,0,0,2,0,1,0,1,0,3,1,0,0,3,3 3 | 5:00,0,0,1,0,1,0,2,1,0,0,0,2,2,2,0,1,0,0,7,3,1,1,1,1,3 4 | 10:00,0,0,1,1,2,0,0,1,0,0,0,0,1,0,0,1,0,1,6,2,0,0,0,2,1 5 | 15:00,1,1,1,2,2,1,0,3,1,2,6,0,0,2,3,1,1,1,0,4,0,0,0,5,2 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Roboflow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🤖 Video Inference Dashboard Example 2 | Roboflow's inference server to analyze video streams. This project extracts insights from video frames at defined intervals and generates informative visualizations and CSV outputs. 3 | 4 | ## 📦 Use Case: Smart Inventory Monitoring 5 | 6 | Factories & stores can: 7 | 8 | - Save time 9 | - Count items at intervals, avoiding stockouts. 10 | - Restock efficiently using data. 11 | - Enhance operations 12 | 13 | ## 📈 Result 14 | 15 | This is counting products on shelf, every 5 minutes, categorically and in total. 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | ![alt text](./results/objects_by_class_over_time.png "Title") 27 | 28 |
29 | 30 | ![alt text](./results/objects_over_time_d.png "Title") 31 | 32 | ## ⚙️ Requirements 33 | 34 | Make sure you have docker installed. Learn more about building, pulling, and running the Roboflow Inference Docker Image in our [documentation](https://roboflow.github.io/inference/quickstart/docker/). 35 | 36 | ## 🔍 Installation 37 | 38 | ### **⌗ 1 Start inference server** 39 | x86 CPU: 40 | 41 | ```bash 42 | docker run --net=host roboflow/roboflow-inference-server-cpu:latest 43 | ``` 44 | NVIDIA GPU 45 | ```bash 46 | docker run --network=host --gpus=all roboflow/roboflow-inference-server-gpu:latest 47 | ``` 48 | 49 | ### **⌗ 2 Setup and Run** 50 | ```python 51 | git clone https://github.com/roboflow/inference-dashboard-example.git 52 | cd inference-dashboard-example 53 | pip install -r requirements.txt 54 | ``` 55 | 56 | ```python 57 | python main.py --dataset_id [YOUR_DATASET_ID] --api_key [YOUR_API_KEY] --video_path [PATH_TO_VIDEO] --interval_minutes [INTERVAL_IN_MINUTES] 58 | 59 | """ 60 | --dataset_id: Your dataset name on Roboflow. 61 | --version_id: The version ID for inference (default: 1). 62 | --api_key: Your API key on Roboflow. 63 | --video_path: Path to the video file for analysis. 64 | --interval_minutes: Interval in minutes to extract predictions (default: 1). 65 | """ 66 | ``` 67 | 68 | ## 🦾 Feedback & Contributions 69 | 70 | Feel free to open an issue, submit a PR, or share your feedback. All contributions are welcome! -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import pandas as pd 3 | import pickle 4 | import requests 5 | import matplotlib.pyplot as plt 6 | import argparse 7 | import os 8 | 9 | 10 | def parse_args(): 11 | parser = argparse.ArgumentParser(description="Process video and extract insights") 12 | parser.add_argument("--dataset_id", help="Dataset ID (required)") 13 | parser.add_argument("--version_id", default="1", help="Version ID (default: 1)") 14 | parser.add_argument("--api_key", help="API key (required)") 15 | parser.add_argument("--video_path", help="Path to the video (required)") 16 | parser.add_argument("--interval_minutes", type=int, default=1, help="Interval in seconds (default: 60)") 17 | return parser.parse_args() 18 | 19 | 20 | def extract_frames(video_path, interval_minutes): 21 | cap = cv2.VideoCapture(video_path) 22 | frames = [] 23 | timestamps = [] 24 | fps = int(cap.get(cv2.CAP_PROP_FPS)) 25 | frame_count = 0 26 | 27 | while cap.isOpened(): 28 | ret, frame = cap.read() 29 | if not ret: 30 | break 31 | if frame_count % (fps * interval_minutes) == 0: 32 | frames.append(frame) 33 | timestamps.append(frame_count / fps) 34 | frame_count += 1 35 | cap.release() 36 | return frames, timestamps 37 | 38 | 39 | def fetch_predictions(base_url, frames, timestamps, dataset_id, version_id, api_key, confidence=0.5): 40 | headers = {"Content-Type": "application/x-www-form-urlencoded"} 41 | df_rows = [] 42 | for idx, frame in enumerate(frames): 43 | numpy_data = pickle.dumps(frame) 44 | res = requests.post( 45 | f"{base_url}/{dataset_id}/{version_id}", 46 | data=numpy_data, 47 | headers=headers, 48 | params={"api_key": api_key, "confidence": confidence, "image_type": "numpy"} 49 | ) 50 | predictions = res.json() 51 | 52 | for pred in predictions['predictions']: 53 | time_interval = f"{int(timestamps[idx] // 60)}:{int(timestamps[idx] % 60):02}" 54 | row = { 55 | "timestamp": time_interval, 56 | "time": predictions['time'], 57 | "x": pred["x"], 58 | "y": pred["y"], 59 | "width": pred["width"], 60 | "height": pred["height"], 61 | "pred_confidence": pred["confidence"], 62 | "class": pred["class"] 63 | } 64 | df_rows.append(row) 65 | 66 | df = pd.DataFrame(df_rows) 67 | df['seconds'] = df['timestamp'].str.split(':').apply(lambda x: int(x[0])*60 + int(x[1])) 68 | df = df.sort_values(by="seconds") 69 | return df 70 | 71 | def plot_and_save(data, title, filename, ylabel, stacked=False, legend_title=None, legend_loc=None, legend_bbox=None): 72 | plt.style.use('dark_background') 73 | data.plot(kind='bar', stacked=stacked, figsize=(15,7)) 74 | plt.title(title) 75 | plt.ylabel(ylabel) 76 | plt.xlabel('Timestamp (in minutes:seconds)') 77 | 78 | if legend_title: 79 | plt.legend(title=legend_title, loc=legend_loc, bbox_to_anchor=legend_bbox) 80 | 81 | plt.tight_layout() 82 | plt.savefig(filename) 83 | 84 | def main(): 85 | args = parse_args() 86 | base_url = "http://localhost:9001" 87 | video_path = args.video_path 88 | dataset_id = args.dataset_id 89 | version_id = args.version_id 90 | api_key = args.api_key 91 | interval_minutes = args.interval_minutes * 60 92 | 93 | 94 | frames, timestamps = extract_frames(video_path, interval_minutes) 95 | df = fetch_predictions(base_url, frames, timestamps, dataset_id, version_id, api_key) 96 | 97 | if not os.path.exists("results"): 98 | os.makedirs("results") 99 | 100 | #saving predictions response to csv 101 | df.to_csv("results/predictions.csv", index=False) 102 | 103 | # Transform timestamps to minutes and group 104 | df['minutes'] = df['timestamp'].str.split(':').apply(lambda x: int(x[0]) * 60 + int(x[1])) 105 | object_counts_per_interval = df.groupby('minutes').size().sort_index() 106 | object_counts_per_interval.index = object_counts_per_interval.index.map(lambda x: f"{x // 60}:{x % 60:02}") 107 | object_counts_per_interval.to_csv("results/object_counts_per_interval.csv") 108 | 109 | # Quick insights 110 | print(f"Total unique objects detected: {df['class'].nunique()}") 111 | print(f"Most frequently detected object: {df['class'].value_counts().idxmax()}") 112 | print(f"Time interval with the most objects detected: {object_counts_per_interval.idxmax()}") 113 | print(f"Time interval with the least objects detected: {object_counts_per_interval.idxmin()}") 114 | 115 | plot_and_save(object_counts_per_interval, 'Number of Objects Detected Over Time', "results/objects_over_time_d.png", 'Number of Objects') 116 | 117 | # Group by timestamp and class, then sort by minutes 118 | objects_by_class_per_interval = df.groupby(['minutes', 'class']).size().unstack(fill_value=0).sort_index() 119 | objects_by_class_per_interval.index = objects_by_class_per_interval.index.map(lambda x: f"{x // 60}:{x % 60:02}") 120 | objects_by_class_per_interval.to_csv("results/object_counts_by_class_per_interval.csv") 121 | 122 | plot_and_save(objects_by_class_per_interval, 'Number of Objects Detected Over Time by Class', "results/objects_by_class_over_time.png", 'Number of Objects', True, "Object Class", "center left", (1, 0.5)) 123 | 124 | 125 | if __name__ == "__main__": 126 | main() 127 | -------------------------------------------------------------------------------- /results/predictions.csv: -------------------------------------------------------------------------------- 1 | timestamp,time,x,y,width,height,pred_confidence,class,seconds 2 | 0:00,0.02328695193864405,295.5,410.0,73.0,46.0,0.9734150767326355,SM Gemahlen,0 3 | 0:00,0.02328695193864405,227.5,126.5,77.0,101.0,0.5063759088516235,Espresso Aromatisch,0 4 | 0:00,0.02328695193864405,286.0,331.0,76.0,48.0,0.5837204456329346,BW Gemahlen,0 5 | 0:00,0.02328695193864405,252.0,235.5,30.0,65.0,0.6269301772117615,Simo EsElegant,0 6 | 0:00,0.02328695193864405,225.0,235.5,30.0,65.0,0.7168950438499451,Simo KaffeeMild,0 7 | 0:00,0.02328695193864405,309.0,234.0,30.0,68.0,0.7224994897842407,Simo KaffeeKraft,0 8 | 0:00,0.02328695193864405,148.0,495.0,68.0,42.0,0.760189414024353,BW Gemahlen,0 9 | 0:00,0.02328695193864405,192.0,402.0,44.0,58.0,0.7835189700126648,CC Vollmundig 36Pads,0 10 | 0:00,0.02328695193864405,148.5,127.5,83.0,105.0,0.8120909333229065,Barista CC,0 11 | 0:00,0.02328695193864405,144.0,237.0,32.0,64.0,0.8398640751838684,Simo KaffeeMild,0 12 | 0:00,0.02328695193864405,80.5,129.0,83.0,102.0,0.6889695525169373,Barista CB,0 13 | 0:00,0.02328695193864405,304.5,124.0,77.0,106.0,0.8629286289215088,Espresso Aromatisch,0 14 | 0:00,0.02328695193864405,236.5,404.5,49.0,57.0,0.8730306029319763,CC Vollmundig 36Pads,0 15 | 0:00,0.02328695193864405,293.5,546.5,75.0,37.0,0.8773476481437683,SM Gemahlen,0 16 | 0:00,0.02328695193864405,133.0,331.0,76.0,48.0,0.9221301674842834,BM Gemahlen,0 17 | 0:00,0.02328695193864405,197.0,236.5,30.0,65.0,0.923898458480835,Simo KaffeeKraft,0 18 | 0:00,0.02328695193864405,211.0,330.5,72.0,49.0,0.9258190989494324,LG Gemahlen,0 19 | 0:00,0.02328695193864405,116.5,237.0,31.0,64.0,0.9260269999504089,Simo KaffeeMild,0 20 | 0:00,0.02328695193864405,141.5,400.0,57.0,58.0,0.9351334571838379,FM 36Pads,0 21 | 0:00,0.02328695193864405,170.5,237.0,29.0,64.0,0.9723898768424988,Simo KaffeeKraft,0 22 | 0:00,0.02328695193864405,290.0,506.0,76.0,36.0,0.8612465858459473,SM Gemahlen,0 23 | 5:00,0.01930748496670276,167.0,449.5,64.0,65.0,0.7176361083984375,Empty Shelf,300 24 | 5:00,0.01930748496670276,196.5,331.5,37.0,15.0,0.6675833463668823,Price,300 25 | 5:00,0.01930748496670276,253.5,401.5,37.0,13.0,0.6592211723327637,Price,300 26 | 5:00,0.01930748496670276,224.5,234.0,41.0,14.0,0.6565319895744324,Price,300 27 | 5:00,0.01930748496670276,226.0,177.0,66.0,100.0,0.6547722816467285,Barista CC,300 28 | 5:00,0.01930748496670276,331.5,483.0,35.0,12.0,0.623317301273346,Price,300 29 | 5:00,0.01930748496670276,228.0,488.0,36.0,14.0,0.5418887734413147,Discount Price,300 30 | 5:00,0.01930748496670276,229.0,291.5,28.0,63.0,0.611021876335144,Simo KaffeeMild,300 31 | 5:00,0.01930748496670276,156.0,231.0,46.0,16.0,0.6082651019096375,Price,300 32 | 5:00,0.01930748496670276,359.0,237.5,40.0,15.0,0.5633571147918701,Discount Price,300 33 | 5:00,0.01930748496670276,320.5,604.5,33.0,15.0,0.5268151760101318,Price,300 34 | 5:00,0.01930748496670276,201.0,291.0,28.0,64.0,0.726374089717865,Simo KaffeeMild,300 35 | 5:00,0.01930748496670276,157.5,173.5,71.0,99.0,0.6134111881256104,Barista CC,300 36 | 5:00,0.01930748496670276,356.5,182.5,63.0,93.0,0.7265565395355225,Espresso Aromatisch,300 37 | 5:00,0.01930748496670276,282.0,292.0,26.0,62.0,0.8455964922904968,Simo EsKraft,300 38 | 5:00,0.01930748496670276,157.0,173.5,70.0,99.0,0.7499425411224365,Espresso Aromatisch,300 39 | 5:00,0.01930748496670276,170.5,371.0,79.0,50.0,0.9368743300437927,SM Gemahlen,300 40 | 5:00,0.01930748496670276,308.0,292.0,26.0,62.0,0.9308812022209167,Simo KaffeeBW,300 41 | 5:00,0.01930748496670276,150.5,333.0,37.0,14.0,0.7439377903938293,Price,300 42 | 5:00,0.01930748496670276,252.0,370.0,74.0,50.0,0.8929466009140015,BM Gemahlen,300 43 | 5:00,0.01930748496670276,175.0,585.0,74.0,44.0,0.8909624218940735,BW Gemahlen,300 44 | 5:00,0.01930748496670276,228.0,446.0,56.0,66.0,0.8851510286331177,FM 36Pads,300 45 | 5:00,0.01930748496670276,334.0,291.5,26.0,61.0,0.913595974445343,Simo KaffeeKraft,300 46 | 5:00,0.01930748496670276,253.0,580.0,68.0,42.0,0.8637905716896057,SM Gemahlen,300 47 | 5:00,0.01930748496670276,256.0,535.0,68.0,40.0,0.8416116833686829,SM Gemahlen,300 48 | 5:00,0.01930748496670276,172.0,290.5,30.0,65.0,0.8308530449867249,Simo KaffeeMild,300 49 | 5:00,0.01930748496670276,282.5,444.5,51.0,59.0,0.7668347954750061,CC Vollmundig 36Pads,300 50 | 5:00,0.01930748496670276,323.0,365.5,68.0,53.0,0.7589477896690369,Empty Shelf,300 51 | 5:00,0.01930748496670276,256.5,292.0,27.0,62.0,0.875664472579956,Simo EsElegant,300 52 | 10:00,0.019086454063653946,132.5,187.5,27.0,13.0,0.6754971146583557,Price,600 53 | 10:00,0.019086454063653946,178.5,276.5,11.0,13.0,0.5182544589042664,Price,600 54 | 10:00,0.019086454063653946,147.5,273.0,11.0,12.0,0.5438727140426636,Price,600 55 | 10:00,0.019086454063653946,156.5,488.0,49.0,40.0,0.6187127232551575,BW Gemahlen,600 56 | 10:00,0.019086454063653946,161.0,275.0,10.0,12.0,0.6505646109580994,Price,600 57 | 10:00,0.019086454063653946,201.0,242.5,20.0,59.0,0.6649411916732788,Simo KaffeeMild,600 58 | 10:00,0.019086454063653946,237.0,283.0,10.0,12.0,0.665515661239624,Price,600 59 | 10:00,0.019086454063653946,207.0,466.0,52.0,46.0,0.6719003915786743,SM Gemahlen,600 60 | 10:00,0.019086454063653946,130.5,271.5,13.0,11.0,0.6970708966255188,Price,600 61 | 10:00,0.019086454063653946,150.0,374.0,44.0,68.0,0.8394197821617126,BW Bohne,600 62 | 10:00,0.019086454063653946,183.0,240.5,16.0,57.0,0.7613373398780823,Empty Shelf,600 63 | 10:00,0.019086454063653946,178.5,138.5,53.0,87.0,0.7642428874969482,FM 36Pads,600 64 | 10:00,0.019086454063653946,276.0,403.5,44.0,57.0,0.7769483327865601,CC Vollmundig 36Pads,600 65 | 10:00,0.019086454063653946,221.5,244.5,21.0,61.0,0.8210639953613281,Simo KaffeeKraft,600 66 | 10:00,0.019086454063653946,160.5,449.0,47.0,42.0,0.8282526135444641,BW Gemahlen,600 67 | 10:00,0.019086454063653946,153.0,310.5,48.0,45.0,0.8882850408554077,SM Gemahlen,600 68 | 10:00,0.019086454063653946,263.5,324.5,57.0,47.0,0.9415959715843201,LG Gemahlen,600 69 | 10:00,0.019086454063653946,202.5,317.0,53.0,46.0,0.9598554968833923,BM Gemahlen,600 70 | 10:00,0.019086454063653946,129.0,236.5,18.0,55.0,0.7537198662757874,Simo KaffeeKraft,600 71 | 15:00,0.02036092197522521,417.0,498.0,56.0,32.0,0.7214412689208984,SM Gemahlen,900 72 | 15:00,0.02036092197522521,387.0,135.0,50.0,74.0,0.7167350649833679,Espresso Kraftig,900 73 | 15:00,0.02036092197522521,426.0,290.0,40.0,46.0,0.7129066586494446,BM Bohne,900 74 | 15:00,0.02036092197522521,448.0,351.0,20.0,46.0,0.7053572535514832,Simo KaffeeKraft,900 75 | 15:00,0.02036092197522521,491.0,351.5,22.0,47.0,0.6946369409561157,Simo KaffeeKraft,900 76 | 15:00,0.02036092197522521,175.0,132.5,58.0,79.0,0.6903895139694214,Barista CB,900 77 | 15:00,0.02036092197522521,444.5,135.5,59.0,73.0,0.6891908049583435,Espresso Aromatisch,900 78 | 15:00,0.02036092197522521,258.5,405.5,37.0,41.0,0.5880886912345886,CC Vollmundig 36Pads,900 79 | 15:00,0.02036092197522521,192.0,495.0,56.0,34.0,0.6340433359146118,Colombia BBGemahlen,900 80 | 15:00,0.02036092197522521,228.0,134.0,48.0,74.0,0.6322517991065979,Espresso Kraftig,900 81 | 15:00,0.02036092197522521,305.0,405.0,34.0,40.0,0.7298151254653931,Colombia BBBohne,900 82 | 15:00,0.02036092197522521,360.5,406.5,37.0,41.0,0.5838360786437988,Colombia BBBohne,900 83 | 15:00,0.02036092197522521,428.5,350.0,21.0,46.0,0.580676257610321,Simo KaffeeKraft,900 84 | 15:00,0.02036092197522521,222.5,404.5,37.0,41.0,0.5801262855529785,CC Vollmundig 36Pads,900 85 | 15:00,0.02036092197522521,431.0,406.5,34.0,39.0,0.5607403516769409,BW Bohne,900 86 | 15:00,0.02036092197522521,366.0,352.0,20.0,44.0,0.5419747233390808,Simo KaffeeKraft,900 87 | 15:00,0.02036092197522521,227.5,294.0,39.0,44.0,0.6355602145195007,AB Bohne,900 88 | 15:00,0.02036092197522521,277.0,350.5,42.0,47.0,0.735442578792572,CC Vollmundig 36Pads,900 89 | 15:00,0.02036092197522521,334.5,132.5,55.0,81.0,0.7932676076889038,Espresso Kraftig,900 90 | 15:00,0.02036092197522521,396.5,405.0,35.0,42.0,0.7885718941688538,CFino Bohne,900 91 | 15:00,0.02036092197522521,407.0,350.0,20.0,46.0,0.5279561281204224,Simo KaffeeMild,900 92 | 15:00,0.02036092197522521,473.5,499.5,57.0,33.0,0.9718591570854187,BW Gemahlen,900 93 | 15:00,0.02036092197522521,477.0,294.5,62.0,37.0,0.9579463601112366,BM Gemahlen,900 94 | 15:00,0.02036092197522521,471.5,533.0,57.0,30.0,0.9537693858146667,BW Gemahlen,900 95 | 15:00,0.02036092197522521,376.0,294.0,58.0,40.0,0.9221926927566528,LG Gemahlen,900 96 | 15:00,0.02036092197522521,362.0,498.5,56.0,29.0,0.9153338074684143,SM Gemahlen,900 97 | 15:00,0.02036092197522521,469.5,351.5,21.0,47.0,0.9023809432983398,Simo KaffeeKraft,900 98 | 15:00,0.02036092197522521,248.0,496.0,56.0,32.0,0.896979033946991,Colombia BBGemahlen,900 99 | 15:00,0.02036092197522521,386.0,351.0,20.0,44.0,0.8924118280410767,Simo KaffeeMild,900 100 | 15:00,0.02036092197522521,470.0,406.0,40.0,44.0,0.8901169300079346,BW Bohne,900 101 | 15:00,0.02036092197522521,360.5,529.0,55.0,32.0,0.8545306921005249,SM Gemahlen,900 102 | 15:00,0.02036092197522521,304.0,497.5,56.0,33.0,0.8462991118431091,Colombia BBGemahlen,900 103 | 15:00,0.02036092197522521,232.5,351.5,45.0,47.0,0.8362724781036377,FM 36Pads,900 104 | 15:00,0.02036092197522521,505.0,223.0,56.0,68.0,0.8173805475234985,FM Bohne,900 105 | 15:00,0.02036092197522521,248.0,527.0,54.0,32.0,0.8024320602416992,Colombia BBGemahlen,900 106 | 15:00,0.02036092197522521,248.0,464.0,56.0,32.0,0.7905616164207458,Colombia BBGemahlen,900 107 | 15:00,0.02036092197522521,362.0,464.0,58.0,26.0,0.7885833382606506,SM Gemahlen,900 108 | 15:00,0.02036092197522521,503.5,133.5,59.0,79.0,0.7408873438835144,Espresso Aromatisch,900 109 | 15:00,0.02036092197522521,304.5,465.5,57.0,33.0,0.5043758153915405,Colombia BBGemahlen,900 110 | --------------------------------------------------------------------------------