how to plot line with angle 60 degree

Question:

i have some data of colors in RGB, i want to plot it to CIEab color channel in 2d which is use the data of a & b. then i need to separate my data with a line which is 60 degree

i have done plot a&b with this code below :

import cv2
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

image_RGB = np.uint8([[[236,195,187],[224,175,167]  ,[211,160,147]  ,[199,141,130]  ,[182,126,113]  ,[164,106,95]   ,[144, 92, 79]  ,[122, 74, 67]  ,[101, 61, 53]  ,[78, 47, 44]],
                    [[234, 196, 186],[222, 178, 161],[209, 162, 146],[193, 143, 123],[178, 128, 105],[161, 110, 93] ,[142, 93, 77]  ,[121, 77, 61]  ,[99, 63, 49]   ,[77, 49, 39]],
                    [[232, 198, 179],[220, 179, 160],[206, 163, 139],[191, 145, 121],[176, 129, 103],[157, 111, 87] ,[139, 96, 71]  ,[117, 80, 58]  ,[97, 64, 45]   ,[77, 49, 37]],
                    [[229, 200, 177],[218, 182, 155],[204, 163, 136],[188, 147, 119],[170, 129, 99] ,[154, 113, 85] ,[134, 95, 66]  ,[117, 81, 55]  ,[93, 65, 43]   ,[73, 52, 35]],
                    [[225, 199, 176],[213, 182, 152],[200, 165, 133],[185, 149, 117],[167, 131, 99] ,[149, 114, 82] ,[131, 98, 65]  ,[112, 81, 52]  ,[92, 66, 41]   ,[71, 52, 37]],
                    [[224,201,176]  ,[210,184,151]  ,[196,166,130]  ,[181,152,112]  ,[166,132,94]   ,[146,117,77]   ,[126, 100, 63] ,[109, 85, 50]  ,[89, 68, 41]   ,[70, 53, 37]],
                    [[163,107,72]   ,[0,0,0]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]]
                    ])

def toLAB(image, input_type = 'RGB'):
    conversion = cv2.COLOR_BGR2Lab if input_type == 'BGR' else cv2.COLOR_RGB2Lab
    image_LAB = cv2.cvtColor(image, conversion)
    print("LAB : ", image_LAB)

    y,x,z = image_LAB.shape
    LAB_flat = np.reshape(image_LAB, [y*x,z])
    print("LAB FLAT : ", LAB_flat)

    colors = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) if input_type == 'BGR' else image
    colors = np.uint8([[[255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0]],
                       [[255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0]],
                       [[0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0]],
                       [[0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0]],
                       [[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0]],
                       [[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0]],
                       [[0,0,255],  [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0]]
                       ])
    print("colors : ", colors)
    colors = np.reshape(colors, [y*x,z])/255.

    fig = plt.figure()
    ax = fig.add_subplot(111, projection='rectilinear')
    ax.scatter(x=LAB_flat[:,2], y=LAB_flat[:,1], s=10,  c=colors, lw=0)
    ax.set_xlabel('A')
    ax.set_ylabel('B')
    # ax = fig.add_subplot(111, projection='3d')
    # ax.scatter(xs=LAB_flat[:,2], ys=LAB_flat[:,1], zs=LAB_flat[:,0], s=10,  c=colors, lw=0)
    # ax.set_xlabel('A')
    # ax.set_ylabel('B')
    # ax.set_zlabel('L')

    print(colors)
    plt.show()

    return image_LAB 

lab_image = toLAB(image_RGB)

the result what i get is like this
enter image description here

but i don’t know how to make line of 60 degree?

the result i want is like the image below. there is a green line with 60 degrees slope. i want to make the line like that
enter image description here
image from : https://www.researchgate.net/publication/325286809_Brief_overview_of_PANTONE_SkinTone_Guide_chart_in_CIELab_color

Asked By: KEZIA ANGELINE

||

Answers:

I Hope it help

x = [1,2,3,4,5]
y = [1,2,3,4,5]

plt.scatter(x,y)

# blue line start at 1,1 end 5,4
plt.plot((1,5), (1,4), '--')

# orange line start at 1,1 end 5,6 
plt.plot((1,5), (1,6), '-') 

image

plt.plot((x1,x2), (y1,y2), '-')

and use some trigonometry to find x1 x2 and y1 y2

or use

# in this case slope = √3 or 1.732
slope = y2-y1 / x2-x1
plt.axline((0, 0), slope=slope)

you can add my code after this line

...
code before
...

ax.scatter(x=LAB_flat[:,2], y=LAB_flat[:,1], s=10,  c=colors, lw=0)
ax.axline((0, 0), slope=1.732)
ax.set_xlabel('A')

...
code after 
...

slope equation

if you got x1,y1 and x2,y2, use y2-y1 / x2-x1
if you get theta, use tan theta (don’t forget to convert degree to radian) or use google to find tan 60 degree

Reference for pyplot.axline

Possibly duplicate of: How to add line based on slope and intercept in Matplotlib?

Answered By: LCKYN

This code plots two lines:

  1. a 60-degree line (green color) that separates data with minimal misclassification. In this case, one red point is misclassified.

  2. a best-angle-line (magenta color) that separates data perfectly without any misclassification. Note: Even though the line may seem passing through one yellow point and one red point, actually it is passing just above the yellow point and just below the red point. Maximum best angle is found to be 52.12 degrees.

image_RGB = np.uint8([[[236,195,187],[224,175,167]  ,[211,160,147]  ,[199,141,130]  ,[182,126,113]  ,[164,106,95]   ,[144, 92, 79]  ,[122, 74, 67]  ,[101, 61, 53]  ,[78, 47, 44]],
                    [[234, 196, 186],[222, 178, 161],[209, 162, 146],[193, 143, 123],[178, 128, 105],[161, 110, 93] ,[142, 93, 77]  ,[121, 77, 61]  ,[99, 63, 49]   ,[77, 49, 39]],
                    [[232, 198, 179],[220, 179, 160],[206, 163, 139],[191, 145, 121],[176, 129, 103],[157, 111, 87] ,[139, 96, 71]  ,[117, 80, 58]  ,[97, 64, 45]   ,[77, 49, 37]],
                    [[229, 200, 177],[218, 182, 155],[204, 163, 136],[188, 147, 119],[170, 129, 99] ,[154, 113, 85] ,[134, 95, 66]  ,[117, 81, 55]  ,[93, 65, 43]   ,[73, 52, 35]],
                    [[225, 199, 176],[213, 182, 152],[200, 165, 133],[185, 149, 117],[167, 131, 99] ,[149, 114, 82] ,[131, 98, 65]  ,[112, 81, 52]  ,[92, 66, 41]   ,[71, 52, 37]],
                    [[224,201,176]  ,[210,184,151]  ,[196,166,130]  ,[181,152,112]  ,[166,132,94]   ,[146,117,77]   ,[126, 100, 63] ,[109, 85, 50]  ,[89, 68, 41]   ,[70, 53, 37]],
                    [[163,107,72]   ,[0,0,0]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]  ,[255,255,255]]
                    ])

def toLAB(image, input_type = 'RGB'):
    conversion = cv2.COLOR_BGR2Lab if input_type == 'BGR' else cv2.COLOR_RGB2Lab
    image_LAB = cv2.cvtColor(image, conversion)
    #print("LAB : ", image_LAB)

    y,x,z = image_LAB.shape
    LAB_flat = np.reshape(image_LAB, [y*x,z])
#     print("LAB FLAT : ", LAB_flat)

    colors = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) if input_type == 'BGR' else image
    colors = np.uint8([[[255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0]],
                       [[255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0],  [255,0,0]],
                       [[0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0]],
                       [[0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0],  [0,255,0]],
                       [[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0]],
                       [[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0],[255,255,0]],
                       [[0,0,255],  [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0],    [0,0,0]]
                       ])
    
    
    colors = np.reshape(colors, [y*x,z])/255.
    
    # get indices of red and yellow colors
    red_index = np.all(colors==[1.,0.,0.],axis=1)
    yellow_index = np.all(colors==[1.,1.,0.],axis=1)
    
    # slice interesting data points, red and yellow
    LAB_red = LAB_flat[red_index]
    LAB_yellow = LAB_flat[yellow_index]
    
    fig = plt.figure(figsize=(10,8))
    ax = fig.add_subplot(111, projection='rectilinear')
    # plot red points
    ax.scatter(x=LAB_red[:,2], y=LAB_red[:,1], s=10,  c='red', lw=0)
    # plot yellow points
    ax.scatter(x=LAB_yellow[:,2], y=LAB_yellow[:,1], s=10,  c='yellow', lw=0)
    
    # a formula to get y2 given other params
    def get_y(X1,X2,Y1,angle):
        return Y1 + (X2-X1) * np.tan(np.radians(angle))
    
    # (141,135) is one the extreme yellow points that stays close to separator line
    # (141,135) is obtained from LAB_flat data corresponding to yellow color
    # use that as hinge point (x_ref,y_ref) to change angle
    # x0 = 100 is randomly selected for plotting purpose and y0 will be calculated for given angle
    # x2 = 200 is randomly selected for plotting purpose and y2 will be calculated for given angle
    # epsilon, a small value, to keep the line just above the reference yellow hinge point
    
    epsilon = 1e-4
    x_ref = 141.
    y_ref = 135.+ epsilon
    
    x0 = 100.
    x2 = 200.
    
    y0 = get_y(x_ref,x0,y_ref,60)
    y2 = get_y(x_ref,x2,y_ref,60)
    
    # plot the 60-degree green line
    plt.plot((x0,x2),(y0,y2),c='g',label='60-degree-line')
    
    # find the best separating angle 
    LAB_red_X = LAB_red[:,2]
    LAB_red_Y = LAB_red[:,1]
    
    # reduce angle value starting fron 60
    for new_angle in np.arange(60.,40.,-0.01):
        
        # get Y values for all red X values for given angle
        y_pred = get_y(x_ref, LAB_red_X, y_ref, new_angle)
        
        # all actual red points should fall above the line
        if (LAB_red_Y > y_pred).all():
            # we found the best angle
            print(new_angle)
            # stop iteration
            break
    
    # plot a line with the best separating angle
    y0 = get_y(x_ref,x0,y_ref,new_angle)
    y2 = get_y(x_ref,x2,y_ref,new_angle)
    
    # plot the best-degree line (magenta color)
    plt.plot((x0,x2),(y0,y2),'--',c='magenta',label=f'{new_angle:0.2f}-degree-line')
    
    # show image to the interesting region only
    plt.xlim([125,160])
    plt.ylim([125,160])
    
    ax.set_xlabel('A')
    ax.set_ylabel('B')
    plt.legend()
    plt.show()

    return image_LAB 

lab_image = toLAB(image_RGB)
Answered By: rajkumar_data
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.