Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/openUC2/ImSwitch
Browse files Browse the repository at this point in the history
  • Loading branch information
beniroquai committed Jul 27, 2023
2 parents ec032b3 + a84d43a commit c30a5c7
Show file tree
Hide file tree
Showing 7 changed files with 900 additions and 78 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ locai/*
conda/*
conda-out/*
imswitch/ImSwitch/ImSwitch/recordings/*
pip-wheel-metadata/ImSwitch-1.2.1.dist-info/entry_points.txt
pip-wheel-metadata/ImSwitch-1.2.1.dist-info/LICENSE
pip-wheel-metadata/ImSwitch-1.2.1.dist-info/METADATA
pip-wheel-metadata/ImSwitch-1.2.1.dist-info/top_level.txt
53 changes: 26 additions & 27 deletions imswitch/imcontrol/controller/controllers/HyphaController.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
isNIP = True
except:
isNIP = False

import argparse
import asyncio
import logging
Expand Down Expand Up @@ -70,7 +70,7 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__logger = initLogger(self)
self.frame = np.zeros((150, 300, 3)).astype('uint8')

self.asyncio_thread = None

# rtc-related
Expand All @@ -79,28 +79,29 @@ def __init__(self, *args, **kwargs):
port = 8080

self.ssl_context = None
# TODO: Create ID based on user input

# TODO: Create ID based on user input
service_id = "UC2ImSwitch"
server_url = "http://localhost:9000"
server_url = "https://ai.imjoy.io/"

# grab all necessary hardware elements
self.stages = self._master.positionersManager[self._master.positionersManager.getAllDeviceNames()[0]]
self.lasers = self._master.lasersManager[self._master.lasersManager.getAllDeviceNames()[0]]
self.ledMatrix = None #self._master.LEDMatrixManager[self._master.ledMatricesManager.getAllDeviceNames()[0]]

try: self.ledMatrix = self._master.LEDMatrixsManager[self._master.LEDMatrixsManager.getAllDeviceNames()[0]]
except: self.ledMatrix = None

# get the first detector to stream data
self.detector_names = self._master.detectorsManager.getAllDeviceNames()
self.detector = self._master.detectorsManager[self.detector_names[0]]

# start the service
self.start_asyncio_thread(server_url, service_id)

def update(self, detectorName, im, init, isCurrentDetector):
""" Update with new detector frame. """
pass

def start_asyncio_thread(self, server_url, service_id):
loop = asyncio.get_event_loop()
self.asyncio_thread = AsyncioThread(loop)
Expand Down Expand Up @@ -145,7 +146,7 @@ def setLaserActive(self, laserId=0, value=0):
Explanation:
This function allows you to activate or deactivate a laser for fluorescence imaging by setting its enabled state.
The laser to be controlled is specified by its laserId. By default, if no laserId is provided,
The laser to be controlled is specified by its laserId. By default, if no laserId is provided,
the function operates on the laser with ID 0.
The enabled state of the laser is determined by the value parameter. If value is set to 1, the laser is activated,
Expand All @@ -154,7 +155,7 @@ def setLaserActive(self, laserId=0, value=0):
Please note that this function does not return any value.
"""
self.lasers[laserId].setEnabled(value)

def setLaserValue(self, laserId=0, value=0):
"""
Sets the value of a laser.
Expand All @@ -175,9 +176,9 @@ def setLaserValue(self, laserId=0, value=0):
the laser system and should be consulted in the system's documentation.
Please note that this function does not return any value.
"""
"""
self.lasers[laserId].setValue(value)

def setLEDValue(self, ledId=0, value=0):
"""
Sets the value of an LED in an LED matrix.
Expand All @@ -199,7 +200,7 @@ def setLEDValue(self, ledId=0, value=0):
Please note that this function does not return any value.
"""
self.ledMatrix[ledId].setValue(value)

def getImage(self, path="Default.tif"):
"""
Captures a single microscopic image and saves it to a specified path.
Expand Down Expand Up @@ -233,7 +234,7 @@ def getImage(self, path="Default.tif"):
mImage = self.detector.getLatestFrame()
tif.imsave(path,mImage)
return mImage

def setPosition(self, value, axis, is_absolute=True, is_blocking=True):
"""
Moves the microscope stage in the specified axis by a certain distance.
Expand All @@ -250,7 +251,7 @@ def setPosition(self, value, axis, is_absolute=True, is_blocking=True):
Example Use:
# Move the stage 10000 µm in the positive X direction in absolute coordinates and wait for the stage to arrive.
self.setPosition(value=10000, axis="X", is_absolute=True, is_blocking=True)
# move the stage 10000 µm in the negative Y direction in relative coordinates and return immediately.
self.setPosition(value=-10000, axis="Y", is_absolute=False, is_blocking=False)
Expand All @@ -267,7 +268,7 @@ def setPosition(self, value, axis, is_absolute=True, is_blocking=True):
"""
print(f"Moving stage to {value} along {axis}")
self.stages.move(value=value, axis=axis, is_absolute=is_absolute, is_blocking=is_blocking)

def start_service(self, service_id, server_url="https://ai.imjoy.io/", workspace=None, token=None):
client_id = service_id + "-client"
print(f"Starting service...")
Expand All @@ -282,17 +283,12 @@ def start_service(self, service_id, server_url="https://ai.imjoy.io/", workspace
server.register_service(
{
"id": "microscope-control",
"name": "openUC2 Microscope",
"description": "The OpenUC2 Microscope Digital Interface grants precise control over an openuc2 microscope,"\
"featuring essential components like a monochrome camera, laser, LED matrix, focusing stage, and XY stage. "\
"Standout features include easy manipulation of transparent samples with the XY stage, autofocus for accurate "\
"long-distance movements, and fluorescence microscopy capabilities with the laser. The LED matrix enhances phase "\
"contrast, while the monochrome camera captures high-quality grayscale images, facilitating diverse research"\
"applications. Researchers enjoy unparalleled precision and control over their experiments with this powerful tool.",
"name": "openUC2 Microscope",
"description": "OpenUC2 Microscope Interface: Precise control over openuc2 microscope.",# Monochrome camera, laser, LED matrix, focusing stage, XY stage. Easy sample manipulation, accurate autofocus, fluorescence microscopy. LED matrix enhances phase contrast. High-quality grayscale imaging. Unparalleled precision.",
"config":{
"visibility": "protected",
"run_in_executor": True,
"require_context": True,
"require_context": True,
},
"type": "microscope",
"move": self.setPosition,
Expand Down Expand Up @@ -341,6 +337,9 @@ async def recv(self):
if len(img.shape)<3:
img = np.array((img,img,img))
img = np.transpose(img, (1,2,0))
img = img/np.max(img)
img = img*255
img = np.uint8(img)
#img = np.random.randint(0, 155, (150, 300, 3)).astype('uint8')
else:
img = np.random.randint(0, 155, (150, 300, 3)).astype('uint8')
Expand All @@ -366,4 +365,4 @@ async def recv(self):
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# along with this program. If not, see <https://www.gnu.org/licenses/>.
107 changes: 79 additions & 28 deletions imswitch/imcontrol/model/interfaces/hikcamera.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ def _init_cam(self, cameraNo=1, callback_fct=None):
self.camera = MvCamera()

# Select device and create handle
stDeviceList = cast(deviceList.pDeviceInfo[int(cameraNo)], POINTER(MV_CC_DEVICE_INFO)).contents

ret = self.camera.MV_CC_CreateHandle(stDeviceList)
self.stDeviceList = cast(deviceList.pDeviceInfo[int(cameraNo)], POINTER(MV_CC_DEVICE_INFO)).contents
ret = self.camera.MV_CC_CreateHandle(self.stDeviceList)
if ret != 0:
raise Exception("create handle fail! ret[0x%x]", ret)

Expand Down Expand Up @@ -341,30 +341,82 @@ def openPropertiesGUI(self):

def work_thread(self, cam=0, pData=0, nDataSize=0):
if platform == "win32":
stOutFrame = MV_FRAME_OUT()
memset(byref(stOutFrame), 0, sizeof(stOutFrame))
while True:
ret = cam.MV_CC_GetImageBuffer(stOutFrame, 1000)
if None != stOutFrame.pBufAddr and 0 == ret:
#print ("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))
nRet = cam.MV_CC_FreeImageBuffer(stOutFrame)

pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,
stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),
dtype=np.uint8)
self.frame = data.reshape((stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nWidth))

self.SensorHeight, self.SensorWidth = stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nWidth
self.frame_id = stOutFrame.stFrameInfo.nFrameNum
self.timestamp = time.time()
self.frame_buffer.append(self.frame)
self.frameid_buffer.append(self.frame_id)
else:
pass
if self.g_bExit == True:
break

if self.isRGB:
stOutFrame = MV_FRAME_OUT()
memset(byref(stOutFrame), 0, sizeof(stOutFrame))
memset(byref(self.stDeviceList), 0, sizeof(self.stDeviceList))


while True:
if self.g_bExit == True:
break

ret = cam.MV_CC_GetImageBuffer(stOutFrame, 1000)
if None != stOutFrame.pBufAddr and 0 == ret :

nRGBSize = stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 3
stConvertParam = MV_CC_PIXEL_CONVERT_PARAM_EX()
memset(byref(stConvertParam), 0, sizeof(stConvertParam))
stConvertParam.nWidth = stOutFrame.stFrameInfo.nWidth
stConvertParam.nHeight = stOutFrame.stFrameInfo.nHeight
stConvertParam.pSrcData = stOutFrame.pBufAddr
stConvertParam.nSrcDataLen = stOutFrame.stFrameInfo.nFrameLen
stConvertParam.enSrcPixelType = stOutFrame.stFrameInfo.enPixelType
stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed
stConvertParam.pDstBuffer = (c_ubyte * nRGBSize)()
stConvertParam.nDstBufferSize = nRGBSize

ret = cam.MV_CC_ConvertPixelTypeEx(stConvertParam)
if ret != 0:
print ("convert pixel fail! ret[0x%x]" % ret)
sys.exit()

cam.MV_CC_FreeImageBuffer(stOutFrame)

try:
img_buff = (c_ubyte * stConvertParam.nDstLen)()
cdll.msvcrt.memcpy(byref(img_buff), stConvertParam.pDstBuffer, stConvertParam.nDstLen)

data = np.frombuffer(img_buff, count=int(nRGBSize),dtype=np.uint8)
self.frame = data.reshape((stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nWidth, -1))
self.SensorHeight, self.SensorWidth = stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nWidth
self.frame_id = stOutFrame.stFrameInfo.nFrameNum
self.timestamp = time.time()
self.frame_buffer.append(self.frame)
self.frameid_buffer.append(self.frame_id)

except Exception as e:
raise Exception("save file executed failed:%s" % e.message)
finally:
pass


else:
stOutFrame = MV_FRAME_OUT()
memset(byref(stOutFrame), 0, sizeof(stOutFrame))
while True:
ret = cam.MV_CC_GetImageBuffer(stOutFrame, 1000)
if None != stOutFrame.pBufAddr and 0 == ret:
nRet = cam.MV_CC_FreeImageBuffer(stOutFrame)

pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()
cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,
stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)
data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),
dtype=np.uint8)
self.frame = data.reshape((stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nWidth))

self.SensorHeight, self.SensorWidth = stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nWidth
self.frame_id = stOutFrame.stFrameInfo.nFrameNum
self.timestamp = time.time()
self.frame_buffer.append(self.frame)
self.frameid_buffer.append(self.frame_id)
else:
pass
if self.g_bExit == True:
break

if platform in ("darwin", "linux2", "linux"):

# en:Get payload size
Expand Down Expand Up @@ -424,7 +476,6 @@ def work_thread(self, cam=0, pData=0, nDataSize=0):
else:
img_buff = (c_ubyte * nPayloadSize)()
ret = cam.MV_CC_GetOneFrameTimeout(byref(data_buf), nPayloadSize, stDeviceList, 1000)
#print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stDeviceList.nWidth, stDeviceList.nHeight, stDeviceList.nFrameNum))
data = np.frombuffer(data_buf, count=int(stDeviceList.nWidth * stDeviceList.nHeight), dtype=np.uint8)
self.frame = data.reshape((stDeviceList.nHeight, stDeviceList.nWidth))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,6 @@

MAX_EVENT_NAME_SIZE = 128 # < \~chinese 设备Event事件名称最大长度 \~english Max length of event name
MV_MAX_XML_SYMBOLIC_NUM = 64 # \~chinese 最大XML符号数 \~english Max XML Symbolic Number
MV_MAX_SYMBOLIC_LEN = 64 # \~chinese 最大枚举条目对应的符号长度 \~english Max Enum Entry Symbolic Number

MV_MAX_SPLIT_NUM = 8 # \~chinese 分时曝光时最多将源图像拆分的个数 \~english The maximum number of source image to be split in time-division exposure
Loading

0 comments on commit c30a5c7

Please sign in to comment.