Skip to content
This repository has been archived by the owner on Jun 8, 2022. It is now read-only.

Ambient.py #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.so
71 changes: 58 additions & 13 deletions Ambient.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,47 @@
from PIL import ImageGrab #pip3 install Pillow
from openrgb import OpenRGBClient #pip3 install openrgb-python
from openrgb.utils import RGBColor

from sklearn.cluster import KMeans
from collections import Counter
import numpy as np

#//////////////////////////////////////////////////////////////////////////////////////////////////////////
# GLOBAL DEFINES
#//////////////////////////////////////////////////////////////////////////////////////////////////////////
#HEIGHT = 1920 #now using image.size[1] dynamically
#WIDTH = 1200 #now using image.size[0] dynamically
LOOP_INTERVAL = 0.05 # how often we calculate screen colour (in seconds)
DURATION = 3 # how long it takes bulb to switch colours (in seconds)
DECIMATE = 10 # skip every DECIMATE number of pixels to speed up calculation
DURATION = 3 # how long it takes bulb to switch colours (in seconds)
DECIMATE = 100 # sample only 1% of pixels to speed up
K_MEANS = 3 # number of clusters to calculate (returns average color if 1 and dominant color if >1)

XSCREENCAPTURE = True # Set to true if on X11, else false
X_RES = 2560 # Screen pixel in x direction
Y_RES = 1440 # screen pixel in y direction

client = OpenRGBClient() #will only work if you use default ip/port for OpenRGB server. This is an easy fix, read the documentation if need be https://openrgb-python.readthedocs.io/en/latest/

Dlist = client.devices


if XSCREENCAPTURE:
# Use X11 display manager for screen capture
import ctypes
from PIL import Image
LibName = 'prtscn.so' # has to be compiled previously from prtscrn.c
AbsLibPath = os.getcwd() + os.path.sep + LibName # assuming prtscrn.so lives in the same dir
grab = ctypes.CDLL(AbsLibPath)

def grab_screen(x1,y1,x2,y2):
w, h = x2-x1, y2-y1
size = w * h
objlength = size * 3

grab.getScreen.argtypes = []
result = (ctypes.c_ubyte*objlength)()

grab.getScreen(x1,y1, w, h, result)
return Image.frombuffer('RGB', (w, h), result, 'raw', 'RGB', 0, 1)

def SetStatic():
for Device in Dlist:
time.sleep(0.1)
Expand All @@ -36,6 +62,13 @@ def hex_to_rgb(value):
lv = len(value)
return tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3))

# init K-Means model
clt = KMeans(n_clusters = 3, n_init=3, max_iter=200)

# init vars for colors before current
old2 = np.zeros(3)
old = np.zeros(3)

# run loop
while True:
#init counters/accumulators
Expand All @@ -48,21 +81,33 @@ def hex_to_rgb(value):
#//////////////////////////////////////////////////////////////////////////////////////////////////////////
# CALCULATE AVERAGE SCREEN COLOUR
#//////////////////////////////////////////////////////////////////////////////////////////////////////////
image = ImageGrab.grab() # take a screenshot
if XSCREENCAPTURE:
image = grab_screen(0,0,X_RES,Y_RES) # take a screenshot usign X
else:
image = ImageGrab.grab() # take a screenshot using PIL
#print image.size


data = []
for y in range(0, image.size[1], DECIMATE): #loop over the height
for x in range(0, image.size[0], DECIMATE): #loop over the width
color = image.getpixel((x, y)) #grab a pixel
red += color[0]
green += color[1]
blue += color[2]
data.append(color)


red = (( red / ( (image.size[1]/DECIMATE) * (image.size[0]/DECIMATE) ) ) )
green = ((green / ( (image.size[1]/DECIMATE) * (image.size[0]/DECIMATE) ) ) )
blue = ((blue / ( (image.size[1]/DECIMATE) * (image.size[0]/DECIMATE) ) ) )
#cluster and assign labels to the pixels
labels = clt.fit_predict(data)
#count labels to find most popular
label_counts = Counter(labels)
#subset out most popular centroid
dominant_color = clt.cluster_centers_[label_counts.most_common()[0][0]]

# current color is blended with colors 2 frames before to smooth effect
dominant_color += (old + 0.5*old2)
dominant_color /= 2.5
# reset vars for next iteration
old = dominant_color
old2 = old

red, green, blue = dominant_color
#print(red, green, blue)
for Device in Dlist:
Device.set_color(RGBColor(int(red), int(green), int(blue)))
Expand Down
36 changes: 36 additions & 0 deletions prtscn.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include <stdio.h>
#include <X11/X.h>
#include <X11/Xutil.h>
//Compile hint: gcc -shared -O3 -fPIC -Wl,-soname,prtscn -o prtscn.so prtscn.c -lX11
//Credits: https://stackoverflow.com/questions/69645/take-a-screenshot-via-a-python-script-on-linux

void getScreen(const int, const int, const int, const int, unsigned char *);
void getScreen(const int xx,const int yy,const int W, const int H, /*out*/ unsigned char * data)
{
Display *display = XOpenDisplay(NULL);
Window root = DefaultRootWindow(display);

XImage *image = XGetImage(display,root, xx,yy, W,H, AllPlanes, ZPixmap);

unsigned long red_mask = image->red_mask;
unsigned long green_mask = image->green_mask;
unsigned long blue_mask = image->blue_mask;
int x, y;
int ii = 0;
for (y = 0; y < H; y++) {
for (x = 0; x < W; x++) {
unsigned long pixel = XGetPixel(image,x,y);
unsigned char blue = (pixel & blue_mask);
unsigned char green = (pixel & green_mask) >> 8;
unsigned char red = (pixel & red_mask) >> 16;

data[ii + 2] = blue;
data[ii + 1] = green;
data[ii + 0] = red;
ii += 3;
}
}
XDestroyImage(image);
XDestroyWindow(display, root);
XCloseDisplay(display);
}